ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Design Pattern] 데코레이터(Decorator) 패턴 - 디자인 패턴
    CSE/Design Pattern 2015. 6. 13. 10:32

    Pattern #7  데코레이터 패턴




     런타임에 객체의 기능을 추가하기 위하여 사용




     패턴 요약 
      - 객체에 동적으로 추가적인 기능을 추가
     
     주의 
      - 다른 객체에 영향을 주지 않으면서 런타임에 개개의 객체에 다른 기능을 추가하고 싶을 때
      - 상속은 컴파일 타임에 추가 기능이 확정적
     
     
     동기

      당신은 GUI Framework 설계업무를 맡았다. 화면 구성요소들은 일반적으로 가장 기본적인 화면으로부터 조금씩 모습이나 기능을

    확장시켜 나간다. 예를 들면 단순히 특정 영역에 문자열을 보여주는 TextView가 있고, 여기에 스크롤 기능을 추가할 수 있으며, 또한

    바깥 테두리효과를 추가할 수 있다. 기본 객체에 조금씩 기능을 추가시켜 나가고자 할 때 적절한 객체지향적 설계는 ?

       












    해결 방안 1
      - 상속을 이용하여 조금씩 기능을 추가한다.
      
     => 문제점 
        - TextView뿐만 아니라, List, Panel, TreeView,... 등에도 Scroll과 border 기능을 추가하려면, 각 클래스별로 ScrolledName, BorderScrolledName 두개의 클래스를 만들어야한다.
       - 만일 Scroll 기능 없이 Border 만 추가하려면? 각 클래스 별로 BorderName 클래스를 작성해야 한다.
       - 화면 구성 클래스가 N개에 적용될 새로운 추가기능을 넣을 때 마다, N개의 새로운 하위 클래스가 작성된다.

    => 문제발생의 원인은 상속관계를 사용함으로써 추가하려는 기능들이 화면구성 클래스와 결합되어 정적으로(static)고정되어 버리기 때문이다.


    해결 방안 2
      - 화면구성 클래스와 추가 기능(decorator)들을 분리하고, 하나의 화면구성 클래스에 여러 개의 기능(decorator)들이 연결되도록 구성한다.








    해결방안2 클래스다이어그램










    의도
     - 객체에 동적으로 추가적인 역할(responsibility)을 덧붙이기
     - 기능을 확장하는데 있어서 상속 방식이 아닌, 더욱 유연한 기능 확장 방안을 제공

    별칭
     - Wrapper







    적용
     - 다른 객체에 영향을 주지 않으면서, 동적으로 개개의 객체에 다른 역할을 추가 시키고자 할 때
     - 객체의 역할을 동적으로 늘이거나 줄이고자 할 때
     - Subclassing을 통한 역할 추가가 힘들 때


    결과
     - 상속보다는 더 융통성이 좋아짐
     - 클래스 기능이 과다하게 되는 것을 피할 수 있음 => 기능을 확장 받을 객체 자체는 단순하게 유지, 데코레이터 객체와의 조합을 통하여 기능을 확장
     - 데코레이터와 컴포넌트는 동일한 것이 아님 => Decorator 객체가 Component 객체를 투명하게 감싸긴 하지만, 연결되어 있는 객체 자체는 아니다. 그러므로, Component Identity를 가정하여 코딩 하면 안 된다.
     - Lots of little objects => Decorator pattern을 사용하면, 비슷하게 보이는 작은 객체들이 시스템을 이루게 되는 경우가 종종 있다. 이 경우 설계를 잘 이해하는 사람들에게는 쉽게 customize 할 수 있지만, 설계를 이해하고 debug하기는 힘들다.






    예제를 통해 살펴보자.





    Car.java
    1
    2
    3
    4
    5
    6
    package decorator;
     
    public interface Car {
        public void assemble();
    }
     
    cs

     



    BasicCar.java

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    package decorator;
     
    public class BasicCar implements Car {
     
        public void assemble() {
            System.out.print("Basic Car");
        }
     
    }
     
    cs




    CarDecorator.java

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
    package decorator;
     
    public class CarDecorator implements Car {
        protected Car car;
     
        public CarDecorator(Car car) {
            this.car = car;
        }
     
        public void assemble() {
            this.car.assemble();
        }
     
    }
     
    cs



    SportCar.java

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
    package decorator;
     
    public class SportsCar extends CarDecorator {
     
        public SportsCar(Car car) {
            super(car);
        }
     
        public void assemble() {
            car.assemble();
            System.out.print(" Adding features of Sports Car.");
        }
     
    }
     
    cs



    LuxuryCar.java

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    package decorator;
     
    public class LuxuryCar extends CarDecorator {
     
        public LuxuryCar(Car car) {
            super(car);
        }
     
        public void assemble() {
            car.assemble();
            System.out.print(" Adding features of Luxury Car.");
        }
    }
     
    cs



    DecoratorMain.java

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    package decorator;
     
    public class DecoratorMain {
        public static void main(String[] args) {
            Car sportsCar = new SportsCar(new BasicCar());
            sportsCar.assemble();
            System.out.println("\n***");
     
            Car sportLuxuryCar = new SportsCar(new LuxuryCar(new BasicCar()));
            sportLuxuryCar.assemble();
        }
    }
     
    cs








    댓글

Designed by Tistory.