ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Spring - 디자인 패턴
    STUDY/디자인패턴 2021. 5. 10. 12:13

     

    1. 어댑터 패턴(Adapter Pattern)

    - 개방 폐쇄 원칙을 활용한 설계 패턴으로, 서로 다른 두 인터페이스 사이에 통신이 가능하게 하는 것이다. 한 클래스의 인터페이스를 클라이언트에서 사용하고자하는 다른 인터페이스로 변환한다. 어댑터를 이용하면 인터페이스 호환성 문제 때문에 같이 쓸 수 없는 클래스들을 연결해서 쓸 수 있다.

     

    public interface ServiceA {
        public void startServiceA();
        public void stopServiceA();
    }

    public class ServiceAA implements ServiceA {
        @Override
        public void startServiceA() {
            System.out.println("start ServiceA");
        }

        @Override
        public void stopServiceA() {
            System.out.println("stop ServiceA");
        }
    }

     

    public interface ServiceB {
        public void startServiceB();
        public void stopServiceB();
    }

    public class ServiceBB implements ServiceB {
        @Override
        public void startServiceB() {
            System.out.println("start ServiceB");
        }

        @Override
        public void stopServiceB() {
            System.out.println("stop ServiceB");
        }
    }

     

     public class ServiceBAdapter implements ServiceA {
              ServiceB serviceB;

              public ServiceBAdapter(ServiceB serviceB) {
                       this.serviceB= serviceB;
              }

              @Override
              public void startServiceA(){ 
                       serviceB.startServiceB();
              }

              @Override
              public void stopServiceA() {
                       serviceB.stopServiceB();
              }
     }

     

    public class ServiceATestDrive {
              public static void main(String[] args) {
                      ServiceAA serviceA = new ServiceAA();
                      
                      ServiceBB serviceB = new ServiceBB();
                      ServiceA serviceBAdapter = new ServiceBAdapter(serviceB);
             
                      System.out.println("ServiceB...");
                      serviceB.startServieB();
                      serviceB.stopServiceB();

                      System.out.println("ServiceA...");
                      testService(serviceA);

                      System.out.println("ServiceBAdapter...");
                      testService(serviceBAdapter);
              }

              public static void testService(ServiceA serviceA){ 
                       serviceA.startServiceA();
                       serviceA.stopServiceA();
              }
     }

     

    [결과]
    ServiceB...
    start ServiceB
    stop ServiceB

    ServiceA...
    start ServiceA
    stop ServiceA

    ServiceBAdapter...
    start ServiceB
    stop ServiceB

     

    2. 프록시 패턴(Proxy Pattern)

    - 실제 서비스 메소드의 반환값에 가감하는 것을 목적으로 하지 않고 제어의 흐름을 변경하거나 다른 로직을 수행하기 위해 사용하는 것으로, 즉 제어 흐름을 조정하기 위한 목적으로 중간에 대리자를 두는 패턴이다.

    • 대리자는 실제 서비스와 같은 이름의 메서드를 구현한다. 이때 인터페이스를 사용한다.
    • 대리자는 실제 서비스에 대한 참조 변수를 갖는다(합성).
    • 대리자는 실제 서비스의 같은 이름을 가진 메서드를 호출하고 그 값을 클라이언트에게 돌려준다.
    • 대리자는 실제 서비스의 메서드 호출 전후에 별도의 로직을 수행할 수도 있다.

     

    public interface IService {
        String runSomething();
    }

    public class Service implements IService {
        public String runSomething() {
            return "service";
        }
    }

    public class Proxy implements IService {
        IService service1;

        public String runSomething() {
            System.out.println("호출에 대한 흐름 제어가 주목적, 반환 결과를 그대로 전달");

            service1 = new Service();
            return service1.runSomething();
        }
    }

     

    public class ClientWithProxy {
        public static void main(String[] args) {
            Iservice proxy = new Proxy();
            System.out.println(proxy.runSomething());  
        }
    }

     

    [결과]
    호출에 대한 흐름 제어가 주목적, 반환 결과를 그대로 전달
    service

     

    3. 데코레이터 패턴(Decorator Pattern)

    - 프록시 패턴과 동일한 구조를 갖는 패턴으로, 프록시 패턴과는 달리 메서드 호출의 반환값에 변화를 주기 위해 중간에 장식자를 두는 패턴이다.

    • 장식ㅈ는 실제 서비스와 같은 이름의 메서드를 구현한다. 이때 인터페이스를 사용한다.
    • 장식자는 실제 서비스에 대한 참조 변수를 갖는다(합성).
    • 장식자는 실제 서비스의 같은 이름을 가진 메서드를 호출하고, 그 반환값에 장식을 더해 클라이언트에게 돌려준다.
    • 장식자는 실제 서비스의 메서드 호출 전후에 별도의 로직을 수행할 수도 있다.

     

    public interface IService {
        String runSomething();
    }

    public class Service implements IService {
        public String runSomething() {
            return "service";
        }
    }

    public class Decorator implements IService {
        IService service1;

        public String runSomething() {
            System.out.println("호출에 대한 장식 주목적, 클라이언트에게 반환 결과에 장식을 더하여 전달");

            service1 = new Service();
            return "decorator " + service1.runSomething();
        }
    }

     

    public class ClientWithProxy {
        public static void main(String[] args) {
            Iservice decorator = new Decorator();
            System.out.println(decorator.runSomething());  
        }
    }

     

    [결과]
    호출에 대한 장식 주목적, 클라이언트에게 반환 결과에 장식을 더하여 전달
    decorator service

     

    4. 싱글턴 패턴(Singleton Pattern)

    - 인스턴스를 하나만 만들어서 사용하기 위한 패턴이다.

    - 싱글톤 패턴에 필요한 요소

    • new를 실행할 수 없도록 생성자에 private 접근 제어자를 지정한다.
    • 유일한 단일 객체를 반환할 수 있는 정적 메서드가 필요하다.
    • 유일한 단일 객체를 참조할 정적 참조 변수가 필요하다.

     

    - 싱글톤 패턴의 특징

    • private 생성자를 갖는다.
    • 단일 객체 참조 변수를 정적 속성으로 갖는다.
    • 단일 객체 참조 변수가 참조하는 단일 객체를 반환하는 getInstance() 정적 메서드를 갖는다.
    • 단일 객체는 쓰기 가능한 속성을 갖지 않는 것이 정석이다.

     

    public class Singleton {
        static Singleton singletonObject;

        private Singleton() { };

        public static Singleton getInstance() {
            if(singletonObject == null) {
                singletonObject = new Singleton();
            }

            return singletonObject;
        }
    }

     

    public class ClientWithSingleton{
        public static void main(String[] args) {
            //private 생성자이기때문에 new를 통해 인스턴스를 생성할 수 없다.
            // Singleton s = new Singleton();

            Singleton s1 = Singleton.getInstance();
            Singleton s2 = Singleton.getInstance();
            Singleton s3 = Singleton.getInstance();
            
            System.out.println(s1);
            System.out.println(s2);
            System.out.println(s3);
        }
    }

     

    [결과]
    SingletonPattern.Singleton@263c8db9
    SingletonPattern.Singleton@263c8db9
    SingletonPattern.Singleton@263c8db9

     

    5. 템플릿 메서드 패턴(Template Method Pattern)

    - 상위 클래스의 견본 메서드에서 하위 클래스가 오버라이딩한 메서드를 호출하는 패턴이다.

    - 구성요소

    • 템플릿 메서드 : 공통 로직을 수행, 로직 중에 하위 클래스에서 오버라이딩한 추상 메서드/훅 메서드를 호출
    • 템플릿 메서드에서 호출하는 추상 메서드 : 하위 클래스가 반드시 오버라이딩 해야한다.
    • 템플릿 메서드에서 호출하는 훅(Hook, 갈고리) 메서드 : 하위 클래스가 선택적으로 오버라이딩한다.

     

    public abstract class Service{
        //템플릿 메서드
        public void runService() {
            System.out.println("start");
            service();
            run();
            System.out.println("stop");
        }

        // 추상 메서드
        abstract void service();
     
       // Hook 메서드
        void run(){
            System.out.println("run service");
        }
    }

     

    public class ServiceA extends Service{
        @Override
        // 추상 메서드 오버라이딩
        void service() {
            System.out.println("serviceA");
        }

        @Override
        // Hook 메서드 오버라이딩
        void run() {
            System.out.println("run ServiceA");
        }
    }

    public class ServiceB extends Service{
        @Override
        // 추상 메서드 오버라이딩
        void service() {
            System.out.println("serviceB");
        }

        @Override
        // Hook 메서드 오버라이딩
        void run() {
            System.out.println("run ServiceB");
        }
    }

     

    public class MainService{
        public static void main(String[] args){
            Service serviceA = new ServiceA();
            Service serviceB = new ServiceB();

            serviceA.runService();
            System.out.println();
            serviceB.runService();
        }
    }

     

    [결과]
    start
    serviceA
    run ServiceA
    stop

    start
    serviceB
    run ServiceB
    stop

     

    6. 팩터리 메서드 패턴(Factory Method Pattern)

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

     

    public abstract class MainService{
        // 추상 팩터리 메서드
        abstract Service getService();
    }

    // 팩터리 메서드가 생성할 객체의 상위 클래스
    public abstract class Service{
        abstract void run();
    }

     

    public class ServiceA extends MainService{
        // 추상 팩터리 메서드 오버라이딩
        @Override
        Service getService(){
            return new ServiceAA(); 
        }
    }

    // 팩터리 메서드가 생성할 객체
    public class ServiceAA extends Service{
        public void run() {
            System.out.println("run serviceA);
        }
    }


    public class ServiceB extends MainService{
        // 추상 팩터리 메서드 오버라이딩
        @Override
        Service getService(){
            return new ServiceBB(); 
        }
    }

    // 팩터리 메서드가 생성할 객체
    public class ServiceBB extends Service{
        public void run() {
            System.out.println("run serviceB);
        }
    }

     

    public class RealService{
        public static void main(String[] args){
            //팩터리 메서드를 보유한 객체들 생성
           MainService serviceA = new ServiceA();
           MainService serviceB = new ServiceB();

           //팩터리 메서드가 반환하는 객체들
           Service serviceAA = serviceA.getService();
           Service serviceBB = serviceB.getService();

           //팩터리 메서드가 반환한 객체들을 사용
           serviceAA.run();
           serviceBB.run();
        }
    }

     

    [결과]
    run serviceA
    run serviceB

     

    7. 전략 패턴(Strategy Pattern)

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

    • 전략 메서드를 가진 전략 객체
    • 전략 객체를 사용하는 컨텍스트(전략 객체의 사용자/소비자)
    • 전략 객체를 생성해 컨텍스트에 주입하는 클라이언트(제3자, 전략 객체의 공급자)

     

    public interface Strategy{
        public abstract void runStrategy();
    }

    public class StrategyA implements Strategy{
        @Override
        public void runStrategy(){
            System.out.println("strategy A");
        }
    }

    public class StrategyB implements Strategy{
        @Override
        public void runStrategy(){
            System.out.println("strategy B");
        }
    }

    public class StrategyC implements Strategy{
        @Override
        public void runStrategy(){
            System.out.println("strategy C");
        }
    }

     

    public class Context{
        void runContext(Strategy strategy){
            System.out.println("start");
            strategy.runStrategy();
            System.out.println("stop);
        }
    }

     

     public class Client{
        public static void main(String[] args){
            Strategy strategy = null;
            Context context = new Context();

            strategy = new StrategyA();
            context.runContext(strategy);

            System.out.println();

            strategy = new StrategyB();
            context.runContext(strategy);
         
            System.out.println();

            strategy = new StrategyC();
            context.runContext(strategy);
        }
    }

     

    [결과]
    start
    strategy A
    stop

    start
    strategy B
    stop

    start
    strategy C
    stop

     

    8. 템플릿 콜백 패턴(Template Callback Pattern - 견본/회신 패턴)

    - 전략을 익명 내부 클래스로 구현한 전략 패턴

    - DI(의존성 주입)에서 사용하는 특별한 형태의 전략 패턴이다.

     

    public interface Strategy{
        public abstract void runStrategy();
    }

    public class Context{
        void runContext(String strategyElement){
            System.out.println("start");
            executeStrategy(strategyElement).runStrategy();
            System.out.println("stop);
        }
    }

    private Strategy executeStrategy(final String strategyElement) {
        return new Strategy(){
            @Override
            public void runStrategy(){
                System.out.println(strategyElement);
            }
        }
    }

     

     public class Client{

        public static void main(String[] args){
            Context context = new Context();

            context.runContext("strategy A");

            System.out.println();

            context.runContext("strategy B");

            System.out.println();

            context.runContext("strategy C");
        }
    }

     

    [결과]
    start
    strategy A
    stop

    start
    strategy B
    stop

    start
    strategy C
    stop

     

Designed by Tistory.