티스토리 뷰

스프링 프레임워크의 공식적인 정의는, 자바 엔터프라이즈 개발을 편하게 해주는 오픈소스 경량급 애플리케이션 프레임워크입니다. 스프링은 객체 지향의 특성과 설계 원칙을 극한까지 적용한 프레임워크이기에 스프링을 익힌다면 디자인패턴이 적용된다는 것을 알 수 있죠.

 

앞서배운 객체지향의 4대원칙과 설계 5원칙 그리고 디자인 패턴을 요리에 비유하자면,

 

요리도구 - 4대 원칙(캡! 상추다)

요리도구 사용법 - 설계원칙(SOLID)

레시피 - 디자인패턴

 

과 같습니다.

 

정보처리기사에서 알려주는 디자인 패턴은 33개인데 생성패턴 5개, 구조패턴 7개, 행위패턴 11개로 구성되어 있습니다.

책에서는 8개 정도 구성되어 있는데 궁금하신 분들은 나머지 패턴도 공부하면 좋을 듯합니다. ㅎㅎ

 

 

1) 어댑터 패턴 - 구조패턴

 

어댑터 뜻을 번역하자면 변환기라고 할 수 있습니다. 서로 다른 두 인터페이스 사이에 통신이 가능하도록 하는 것이죠. 예시를 들자면 휴대폰 충전기의 경우 휴대폰을 직접 전원 콘센트에 연결할 수 없기 때문에 충전기가 핸드폰과 전원 콘셉트 사이에서 둘을 연결해주는 변환기의 역활을 수행합니다.

 

어댑터 패턴은 DBMS을 공통의 인터페이스인 JDBC, ODBC를 이용해 조작하는데 이것이 어댑터 패턴을 이용하는 개방폐쇄원칙(OCP)를 이용하는 것입니다.

 

ServiceA {  void runServiceA( ){ ... } }

 

ServiceB {  void runServiceB( ){ ... } }

 

main에서 각각의 Service 객체를 만들어 runServiceA, B 메서드를 호출하는 것과

 

AdapterServiceA { 

        

        ServiceA serviceA;    

    

        void runService( ){ serviceA.runServiceA( ); }

}

 

,

 

AdapterServiceB {

        

        ServiceB serviceB;    

    

        void runService( ){ serviceB.runServiceB( ); }

}

 

중간에서 변환해주는 클래스를 생성해 같은 메서드 이름인 runService를 호출하는 점.

 

호출당하는 쪽의 메서드를 호출하는 쪽의 코드에 대응하도록 중간에 변환기를 통해 호출하는 패턴이라고 볼 수 있습니다.

 

이런식으로 사용한다면 기존 코드의 재사용성을 높이는 장점이  있겠죠? 하지만 단점또한 존재하는데 새로운 어댑터클래스를 만들면 대부분 상속이 있어 유연성이 부족할 가능성이 존재합니다.

 

+ 어댑터 패턴에 더 궁금하신 분은 이 사이트를 참고해보세요!

 

https://kscory.com/dev/design-pattern/adapter

 

Cory's Developing & Life.

Cory's Developing & Life.

kscory.com

 

 

 

2) 프록시 패턴 - 구조패턴

 

프록시는 대리자, 대변인이라는 뜻을 가지는 단어입니다. 누군가를 대신해 그 역할을 수행하는 존재이죠.

 

프록시 패턴의 가장 큰 특징은 실제 서비스 객체가 가진 메서드와 같은 이름의 메서드를 사용하는데 이를 위해 인터페이스를 사용합니다. 이 때 서비스 객체가 들어갈 자리에 대리자 객체를 대신 투입해 클라 쪽에서는 실제 서비스 객체를 통해 메서드를 호출하고 반환값을 받는지, 대리자 객체를 통해 메서드를 호출하고 반환값을 받는지 전혀 모르게 처리도 가능합니다.

 

말로하면 어렵죠 ㅠㅠ 하지만 코드로 보면 간단합니다!

 

Interface IService { String runSomething( ); }

 

=> 구현!

class Service implements IService{

      String runSomething( ){ ... }

}

 

=> 구현!

class Proxy implements IService{

 

      IService service;

 

      String runSomething( ){ 

         

          System.out.println("호출에 대한 흐름 제어, 반환 결과 전달 또는 별도의 로직 예를 들면 검사같은 것들?");

          service = new Service( );

          return service.runSomething( );

 

      }

}

 

즉 하나의 인터페이스에 두개 이상의 클래스를 구현받아 프록시 클래스에 같은 메서드 안에 서비스를 넣어 투명하게 보여 보안에서도 쓰이며 다른 로직을 수행하기 위해 사용합니다. Proxy 패턴은 OCP, DIP 설계원칙이 적용되어 바꾸고자 하는 서비스를 인터페이스로 두어 교체를 하더라도 영향받지 않게합니다.

 

장점은 사전처리, 단점은 코드의 복잡성 정도 입니다. 물론 장단점은 많지만 추려서 하나 정도 써봤습니다;;

 

+ 프록시 패턴에 더 궁금하신 분은 이 사이트를 참고해보세요!

 

https://coding-factory.tistory.com/711

 

[Design Pattern] 프록시 패턴(Proxy Pattern)에 대하여

프록시 패턴이란? 프록시는 대리인이라는 뜻으로, 무엇인가를 대신 처리하는 의미입니다. 일종의 비서라고 생각하시면 됩니다. 사장님한테 사소한 질문을 하기보다는 비서한테 먼저 물어보는

coding-factory.tistory.com

 

 

3) 데코레이터 패턴 - 구조패턴

 

프록시와 구현방법은 같으나, 반환값을 조작하지 않는 프록시 패턴과 달리 반환값에 추가, 가감을 입히는 패턴입니다.

메서드 호출의 반환값에 변화를 주기 위해 중간에 장식자를 두는 패턴이죠. 프록시와 똑같이 OCP, DIP 설계원칙이 적용되어있습니다!

 

class Deco implements IService{

 

      IService service;

 

      String runSomething( ){ 

         

          System.out.println("호출에 대한 흐름 제어, 반환 결과 전달 또는 별도의 로직 예를 들면 검사같은 것들?");

          service = new Service( );

          return 수정본 + service.runSomething( );

 

      }

}

 

 

하지만 이렇게 만들면 추가적으로 데코를 하고싶을 때 어려움이 있습니다.

 

그래서,

 

IService를 구현받는 기본 클래스를 만들고, 데코레이터 클래스를 만들어 멤버변수에 IService를 넣어 차례대로 구현받고 나타낼 수 있는 것이 좋습니다.

 

Interface IService { String runSomething( ); }

 

=> 구현!

class Service implements IService{

      String runSomething( ){ ... }

}

 

=> 구현!

 

class ServiceDeco implements IService{

 

      IService service;

 

      // 생성자!

      ServiceDeco(IService service){ 

         this.service = service;

      }

 

      String runSomething( ){

              service.runSomething( );

      }

 

}

 

,

 

class ServiceDecoOne implements ServiceDeco{

 

      ServiceDecoOne(IService service){

         super(service);

      }

 

      String runSomething( ){

              super.runSomething( );

              this.one( );

      }

 

      void one( ){ ... }

 

}

 

,

 

class ServiceDecoTwo implements ServiceDeco{

 

      ServiceDecoTwo(IService service){

         super(service);

      }

      String runSomething( ){

              super.runSomething( );

              this.two( );

      }

 

      void two( ){ ... }

 

}

 

이를 실행해보면!!!

 

public static void main(String[] args) {
      IService basicAndOneWithTwo =
      new ServiceDecoOne(
      new ServiceDecoTwo(
      new Service( ) ) );
      basicAndOneWithTwo.runSomething( );
  }

 

Service -> ServiceDecoTwo -> ServiceDecoOne 순으로 실행이 됩니다! 일종의 체인이라고 생각하시면 편합니다!

 

 

+ 데코레이터 패턴에 더 궁금하신 분은 이 사이트를 참고해보세요.

 

https://gmlwjd9405.github.io/2018/07/09/decorator-pattern.html

 

[Design Pattern] 데코레이터 패턴이란 - Heee's Development Blog

Step by step goes a long way.

gmlwjd9405.github.io

 

 

 

4) 싱글턴 패턴 - 생성패턴

 

인스턴스를 하나만 만들어 메모리 관리를 용이하게 사용하기 위한 패턴입니다. 커넥션 풀, 스레드 풀 등 인스턴스를 여러개 만들면 메모리가 금세 차기에 매우 비효율적입니다. 그러기에 인스턴스를 하나만 만들어서 계속 재사용할 수 있게 하는 것이 목적이죠.

 

class Singleton{

    static Singleton singletonObject;

 

    //내부에만 접근하도록!

    private Singleton( ){ }; 

    

   //객체 반환 정적 메서드

   public static Singleton getInstance( ){

      if(singletonObject == null ){

         singletonObject = new Singleton( );

      }

   }

}

 

핵심은 private 생성자, 그리고 객체 반환 Static 정적 메서드를 통해 인스턴스를 받아오는데 비어있으면 한번만 생성하는 것이 포인트입니다.

 

사용을 언제할까요?

 

제가 애니팡 게임을 개발을 할 때 뮤직매니저든 로직매니저든 접근하는 경우가 있었습니다. 하지만 매니저를 여러개 있을 필요도 없고 메모리만 차지하는 경우가 있었을 때 이 싱글톤 패턴을 이용하니 꽤 나아진 코드가 된 경험이 있습니다. 즉 중요한 객체인데 절대 바뀌지 않을 객체에 선언하는 것이 저는 옳다고 생각합니다! (본인 1인 캐릭터 같은 것들)

 

 

 

 

5) 템플릿 메서드 패턴 - 행위패턴

 

전체 일을 수행하는 구조는 바꾸지 않으면서 특정 단계에서 수행하는 내역을 바꾸는 패턴입니다.

 

// 추상 클래스


abstract class Animal{

   

   //핵심. 전체 일 수행 구조를 바꾸지 않습니다! play와 runSomething 메서드만 바뀜!

   void common( ){

       ...

       play( );

       runSomething( );

       ...

   }

   

   // 추상 메서드

   abstract void play( );

   

  // 일반 메서드

   void runSomething( ){ ... };

 

}

 

,

 

class Dog extends Animal{

   

   //추상 메서드 오버라이딩 ( 무조건 구현 )

   @Override 

    void play( ){ ... };

 

   // 메서드 오버라이딩 ( 특이한 거 아니면 딱히 구현할 필요는 없다. )

    @Override

    void runSomething( ){ ... };

}

 

,

 

class Cat extends Animal{

   

   //추상 메서드 오버라이딩 ( 무조건 구현 )

   @Override 

    void play( ){ ... };

 

   // 메서드 오버라이딩 ( 특이한 거 아니면 딱히 구현할 필요는 없다. )

    @Override

    void runSomething( ){ ... };

}

 

 

// 사용 

 

public static void main(String[] args) {
    Animal bolt = new Dog( );

    bolt.common( ); 

 

    //**********************//

 

   Animal kitty = new Cat( );

   kitty.common( ); 

    
}

 

즉 common 메서드에 대한 공통로직은 바뀌지 않으며 다른 상속 객체에 대한 메서드만 바꾸는 점을 알 수 있습니다!

 

 

+ 템플릿 메서드 패턴에 더 궁금하신 분은 이 사이트를 참고해보세요.

 

https://gmlwjd9405.github.io/2018/07/13/template-method-pattern.html

 

[Design Pattern] 템플릿 메서드 패턴이란 - Heee's Development Blog

Step by step goes a long way.

gmlwjd9405.github.io

 

 

6) 팩토리 메서드 패턴 - 생성패턴

 

객체를 생성 반환하는 메서드 생성패턴입니다. 하위클래스에서 팩터리 메서드를 오버라이딩해서 객체를 반환하게 하는 것을 의미합니다. 여기서 super, extends 키워드를 통해 제한을 걸어 오류를 방지하는 방법도 있습니다만 어려운 부분이므로 건너가겠습니다.

 

오버라이드 된 메서드가 객체를 반환하는 패턴

 

abstarct class Animal{

    abstract AnimalToy getToy( );

}

 

class Dog extends Animal{

    AnimalToy getToy( ){

        return new DogToy( );

    }

}

 

,

 

abstract class AnimalToy{

    abstract void identify( );

}

 

class DogToy extends AnimalToy{

    void identify( ){ ... }

}

 

=> Dog 클래스에서 getToy를 통해 새로운 객체인 DogToy 인스턴스를 리턴합니다.

 

팩토리 메소드 패턴을 사용하는 경우 직접 객체를 생성해 사용하는 것을 방지하고 서브 클래스에 위임함으로써 보다 효율적인 코드 제어를 할 수 있고 의존성을 제거합니다.

 

+ 팩토리 메서드 패턴에 더 궁금하신 분은 이 사이트를 참고해보세요.

 

https://jdm.kr/blog/180

 

팩토리 메소드 패턴(Factory Method Pattern) :: JDM's Blog

이번 포스팅은 팩토리 메소드 패턴Factory Method Pattern에 대해 알아보고자 합니다. Factory Method Pattern 기본적으로 팩토리는 공장이란 뜻을 내포하고 있습니다. 따라서 팩토리 메소드 패턴도 무언가

jdm.kr

 

 

 

7) 전략패턴 - 행위패턴

 

클라이언트가 전략을 생성해 전략을 실행할 컨텍스트에 주입하는 패턴

 

주요 요소는 1. 전략 메서드를 가진 전략 객체, 2. 전략 객체를 사용하는 컨텍스트, 3. 전략 객체를 생성해 컨텍스트에 주입하는 클라이언트 3가지 입니다.

 

1. 전략 객체

 

interface Strategy{

   abstract void runStrategy( );

}

 

class StrategyGun implements Strategy{

   @Override

    void runStrategy( ){ ... }

}

 

class StrategySword implements Strategy{

   @Override

    void runStrategy( ){ ... }

}

 

 

2. 전략 객체를 사용할 컨텍스트

 

class Soldier{

  Strategy strategy;

 

  Soldier(Strategy strategy){

     this.strategy = strategy; 

  }

 

   void runContext( ){

         ...

         strategy.runStrategy( );

         ...

   }

}

 

 

3. 클라이언트

 

여기서는 메인함수 클라이언트를 쓴다고 가정하며 전략과 군인 인스턴스를 생성하며 사용합니다.

 

 

언뜻 보면 템플릿 메서드 패턴과 비슷하며 실제로도 유사합니다. 같은 문제의 솔루션으로 상속이냐 객체의 주입이냐의 차이입니다. 상속은 자바에서 부담이 있기 때문에 전략패턴이 주로 더 쓰이는 경향이 있습니다.

 

+ 전략 패턴에 더 궁금하신 분은 이 사이트를 참고해보세요.

 

https://victorydntmd.tistory.com/292

 

[디자인패턴] 전략 패턴 ( Strategy Pattern )

전략 패턴 ( Strategy Pattern ) 객체들이 할 수 있는 행위 각각에 대해 전략 클래스를 생성하고, 유사한 행위들을 캡슐화 하는 인터페이스를 정의하여, 객체의 행위를 동적으로 바꾸고 싶은 경우

victorydntmd.tistory.com

 

7 - 2) 템플릿 콜백 패턴 - 행위패턴

 

전략 패턴과 유사하며 객체 주입을 익명 클래스로 하는 방법입니다.

 

전략 패턴에서 사용한 Solider, Strategy 클래스를 인용하자면,

 

public static void main(String[] args) {
    Soldier solider = new Soldier(new Strategy( ){

       @Override

        public void runStrategy( ){ ... }

     } );

    solider.runContext( );
}

 

즉 전략에 해당하는 것을 익명클래스로 재정의 한다는 점입니다.

 

 

이상으로 7개의 디자인 패턴을 알아보았습니다. 패턴은 무궁무진 하며 알아두면 나쁘지 않습니다.

 

https://namu.wiki/w/%EB%94%94%EC%9E%90%EC%9D%B8%20%ED%8C%A8%ED%84%B4

 

다음에는 스프링에 대한 내용을 정리해보록 하겠습니다!!

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함