- 예제 코드 Diagram -



* Decorator Patterns

(상속 또는 인터페이스를 이용해 형식(Type)을 맞춤으로서객체에 추가적인 요건을 동적으로 첨가할 수 있다.

Decorator 는 서브클래스를 만드는 것을 통해서 기능을 유연하게 확장할 수 있는 방법을 제공한다.

주의할 건 Decorator 는 상속을 통해서 행동을 물려받는 것이 목적이 아니다!


위 Diagram 를 통해 설명하자면,

- Beverage 가 추상 구성요소 (Component)

- DarkRoast, HouseBlend, Decaf, Espresso 가 구상 구성요소 (Concrete Component)

- CondimentDecorator 가 추상 데코레이터 (Decorator)

- Mocha, SteamMilk, Whip, Soy 가 구상 데코레이터 (Concrete Decorator)


※ Beverage 클래스가 추상 클래스인데, 이는 기존의 코드가 추상 클래스로 되어있었고

기존 코드는 가능한 고치지 않는 것이 좋기 때문에 그대로 쓴 것이다. 인터페이스로 구현하는 것도 가능하다.



* 예제 코드

Beverage beverage = new DarkRoast();
beverage = new Mocha(beverage);
beverage = new Whip(beverage);
System.out.println(beverage.cost());

Beverage 의 구상요소들 cost() 의 내용은

return (음료 가격);


Condiment Decorator 의 구상요소들 cost() 의 내용은

return (데코 가격) + (생성자에서 전달받은 음료).cost();




* java.io 클래스와 Decorator 패턴


(출처:http://i.stack.imgur.com/O7pqc.png)



* OCP (Open-Closed Principle) :

- 클래스는 확장에 대해서는 열려 있어야 하지만 코드 변경에 대해서는 닫혀 있어야 한다 !



* Decorator 패턴의 장점 & 단점

- OCP 에 충실하면서 유연한 디자인을 만들어 낼 수 있다.

- Decorator 를 바로 끼워넣어도 클라이언트 쪽에서는 Decorator 를 사용한다는 것을 전혀 알 수 없다.

- 자잘한 클래스들이 엄청나게 추가되는 경우가 종종 발생해 이해하기 힘든 디자인이 만들어 질 수 있다.

(ex. java.io 클래스)

- Decorator 를 도입하면 구성 요소를 초기화하는 데 필요한 코드가 훨씬 복잡해진다.

구성 요소 인스턴스만 만드는 것 뿐만 아니라 꽤 많은 Decorator 로 감싸는 경우가 자주 발생한다.

(but 이 문제는 차후 다루는 장 ~팩토리, 빌더~ 를 통해 해결할 수 있다고 한다)


* 객체지향의 원칙 :

1) 바뀌는 부분은 캡슐화 한다.

2) 상속보다는 구성을 활용한다.

3) 구현이 아닌 인터페이스에 맞춰서 프로그래밍 한다.

4) 서로 상호작용을 하는 객체 사이에서는 가능하면 느슨하게 결합하는 디자인을 사용해야 한다.

5) 클래스는 확장에 대해서는 열려 있어야 하지만 코드 변경에 대해서는 닫혀 있어야 한다(OCP).



이 장에서의 정리 :

- 상속 또는 인터페이스 구현을 통해서 Decorator 가 감쌀 클래스와 같은 형식을 가지게 된다.

- Decorator 에서는 자기가 감싸고 있는 구성요소의 메소드를 호출한 결과에

 새로운 기능을 더함으로써 행동을 확장한다.

- 구성요소를 감싸는 Decorator 의 갯수에는 제한이 없으나

 자잘한 객체들이 너무 많이 추가될 수 있고, 이로 인해 코드가 필요 이상으로 복잡해질 수도 있다. 

 주의해서 남용하는 일이 없도록 하자!


by kelicia 2014. 5. 18. 02:44