Decorator Pattern은 객체에서 추가적인 요건을 동적으로 추가할 수 있다.
1 2
| Target target = new concreteTarget(); target = new Condition(target);
|
- Decorator 의 super class는 장식할 객체의 super class와 같다.
- Decorator 구현체는 Decorator 추상 class를 상속하여 기능을 추가할 수 있다.
- 한 객체를 여러 개의 Decorator 구현체로 감싸서 기능을 추가할 수 있다.
- Decorator는 장식할 객체에 어떤 행동을 위임하는 것외에도 추가적인 작업을 수행할 수 있다.
- Component는 장식할 객체의 추상 class로 Concrete Component에서 수행해야 할 공통적인 메소드, property를 가지고 있다.
- Decorator는 concrete component에 추가적인 작업을 동적으로 추가하는 Concrete Decorator의 추상 class이다.
decorator pattern 을 이해하기 위해서 , 예시를 가지고 왔다.
카페에서 음료수를 판다고 가정하였을떄, 음료수에 default가격이 있고, 거기에 휘핑크림이나 , mocha 추가하였을떄 추가금액이 붙는다고 가정하자.
이를 상속구조에서 super class에서 추가적인 요건(휘핑크림,모카.. etc)등을 가져간다고 하면 매 첨가물이 추가될떄마다 super class의 코드가 변경되고, subclass를 필요도 없는 method를 상속받을 수도 있다. (OCP에 적합하지 않은 설계)
반면 decorator pattern은 동적으로 행동을 설정할 수 있다.
1 2 3 4 5 6 7 8
| public abstract class Beverage { String description = "none"; public String getDescription(){ return this.description; } public abstract double cost(); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class Espresso extends Beverage{ public Espresso() { this.description = "espresso"; } @Override public double cost() { return 1.99; } }
public class HouseBlend extends Beverage{ public HouseBlend() { this.description = "houseblend"; } @Override public double cost() { return .89; } }
|
1 2 3 4 5
| public abstract class CondimentDecorator extends Beverage{ public abstract String getDescription(); }
|
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 32 33
| public class Mocha extends CondimentDecorator{ private Beverage beverage; public Mocha(Beverage beverage) { this.beverage = beverage; } @Override public double cost() { return .20 + beverage.cost(); } @Override public String getDescription() { return beverage.getDescription() + " mocha"; } }
public class Whip extends CondimentDecorator{
private Beverage beverage; public Whip(Beverage beverage) { this.beverage =beverage; } @Override public double cost() { return .1 + beverage.cost(); } @Override public String getDescription() { return beverage.getDescription() + " whip "; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public class Test {
public static void main(String[] args) { Beverage espresso = new Espresso(); Beverage houseBlend = new HouseBlend();
espresso = new Mocha(espresso); espresso = new Whip(espresso); System.out.println("espresso.getDescription() = " + espresso.getDescription()); System.out.println("espresso.cost() = " + espresso.cost());
houseBlend = new Whip(houseBlend); System.out.println("houseBlend.getDescription() = " + houseBlend.getDescription()); System.out.println("houseBlend.cost() = " + houseBlend.cost()); }
}
|
decorator 적용 예시
대표적으로 Java.io의 Reader/Writer stream이 Decorator pattern을 사용하여 구현되어 있다.
- Head First Design Patterns: A Brain-Friendly Guide (Head First Design Patterns: A Brain-Friendly Guide)