Friday, February 21, 2014

Decorator Pattern

@Desc
 : Decorator pattern은 Component의 기능을 유연하게 확장하기 위해 Sub Class를 이용하는 기법이다.
 : "Component" 란 실제로 우리가 표현하기 원하는 원래의 객체를 의미하고,
 : "Decorator" 는 그러한 Component들의 기능을 확장시켜주는 Wrapper Class로 이해할 수 있다.
 : Decorator는 Component의 Sub Class로 구현되어 Component와 다형성을 형성하기 때문에,
 : 마치 기능이 조금 추가되거나 변경된 Component 자체인 것처럼 여겨질 수 있다. 이러한 특성 때문에
 : Decorator Pattern을 이용하면 원래의 Component의 기능을 유연하게 확장할 수 있게 된다.
 : Decorator Pattern은 몇 가지 단점도 가지고 있는데,
 : 하나는 남들이 이해하기 힘들 정도로 자잘한 클래스들이 엄청나게 추가될 수 있다는 것이다.
 : 둘째는 특정 형식에 의존하는 코드에 Decorator를 적용하기엔 무리가 있다는 것이다.
 : 셋째는 Decorator들이 많기 때문에 Component를 초기화하는 데 필요한 코드가 복잡해진다는 것이다.
 : 마지막 단점은 "Factory Pattern" 이나 "Builder Pattern" 을 이용해서 보완 가능할 수 있다.
 : 요약 결론하면,
 : Decorator Pattern에서는 객체에 추가적인 요건을 동적으로 첨가한다.
 : Decorator는 Sub Class를 만드는 것을 통해서 기능을 유연하게 확장할 수 있는 방법을 제공한다.

@Example
1) Starbuzz Order System을 구현해 보고자 한다. 
2) Starbuzz에는 HouseBlend, DarkRoast, Decaf, Espresso 등의 많은 음료(Beverage)가 있고,
3) 음료에는 Milk, Soy, Mocha, Whip 등 첨가물(Condiment)이 추가될 수 있다.

4) 쉽게 생각하면 Beverage라는 Super Class를 만들고 각 음료마다 Beverage 클래스를 상속할 수 있다.
5) 그리고 각 첨가물에 따른 비용 가감은 Super Class의 Cost() 함수 내에서 처리해야 할 것이다.

6) 그런데, 이 방식은 문제가 많다.
7) 첫째로 첨가물 가격이 바뀔 때마다 Cost() 함수를 계속 수정해야만 하고,
8) 첨가물 종류가 많아지면 Cost() 함수 내부 처리가 복잡해질 수 있다.
9) 만약 새로운 음료 Ice Tea가 출시되었다면 이런 경우 Whip에 대한 처리는 없어야 한다.
10) 상속을 받았기 때문에 Cost() 함수 내용을 그대로 전달받게 되는데, 이것을 변경할 순 있지만
11) 만약 이를 변경하려면 Overriding이 필요하고 이것은 Sub Class의 복잡성을 증가시킨다.
12) 나중에는 어떤 Class가 어떤 첨가물을 추가할 수 있는지 없는지가 혼란스러울 것이다.
13) 여기서 "OCP Principle" 이 사용될 수 있다.

14) Condiment Decorator 클래스를 만들고 Component의 추상클래스인 Beverage를 상속해보자.
15) 그리고 Component 객체를 Decorator에 구성(Composition)으로 추가한다.
16) 즉, Decorator를 생성할 때 Component를 Parameter로 하여 Composition 관계를 만든다.
17) 이렇게 되면 Decorator 동작 시 Component의 동작을 변경하지 않고 기능을 추가할 수 있다.

@Principle
  " Open-Closed Principle " (OCP 원칙)
  : 클래스는 확장에 대해서는 열려 있어야 하지만,
    코드 변경에 대해서는 닫혀 있어야 한다.




@reference
  : Head First Design Patterns
    by Eric Freeman, Elisabeth Freeman, Kathy Sierra, Bert Bates, 1st Ed.

1 comment:

  1. Decorator Pattern을 구현할 때는 Decorator가 상속할 Component Class에서 Destructor를 virtual로 선언해 주어야 한다. 그래야 Wrapping되어 있는 실제 객체의 Destructor를 호출하여 Memory Leak을 방지할 수 있다.

    ReplyDelete