데코레이터 패턴은 객체를 장식하는 패턴이다.
데코레이터 패턴은 객체에 추가 요소를 동적으로 더할 수 있다.
따라서 서브클래스를 만들 때보다 훨씬 유연하게 기능을 확장할 수 있다.
실제 코드를 구현할 때 어떻게 적용하는지는 아래에서 예시를 보며 다시 이해해보자
데코레이터 패턴에 가장 유명한 예시인 주문 시스템을 예로 들어보자.
고객이 모카와 휘핑크림을 추가한 다크 로스트 커피를 주문한다면?
데코레이터 패턴을 적용하여 생각해보면 다음과 같다.
- DarkRoast 객체를 가져온다.
- Mocha 객체로 장식한다.
- Whip 객체로 장식한다.
- cost()메소드를 호출한다. (이때 첨가물의 가격을 계산하는 일은 해당 객체에게 위임한다.
위와 같이 구현하기 위해서
위의 데코레이터 패턴의 구성 요소에서
Beverage라는 Component를 만들고,
Beverage를 상속받아 DarkRoast 라는 ConcreteComponent를 만든다.
(HouseBlend, Decaf 등이 더 있을 수 있겠다)
그리고 CondimentDecorator라는 Decorator를 만들고
그를 상속받아 Mocha, Whip, Milk 등의 첨가물을 나타내는
데코레이터를 구현한다.
Java 코드로 구현하면 아래와 같다.
public abstract class Beverage {
String description = "Unknown Beverage";
public String getDescription() {
return description;
}
public abstract double cost();
}
public class DarkRoast extends Beverage {
public DarkRoast() {
description = "Dark Roast Coffee";
}
public double cost() {
return .99;
}
}
public abstract class CondimentDecorator extends Beverage {
public abstract String getDescription();
}
public class Mocha extends CondimentDecorator {
Beverage beverage;
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Mocha";
}
public double cost() {
return .20 + beverage.cost();
}
}
public class Whip extends CondimentDecorator {
Beverage beverage;
public Whip(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Whip";
}
public double cost() {
return .10 + beverage.cost();
}
}
자 이제 준비가 끝났으니
음료 인스턴스를 만들고, 첨가물 데코레이터로 장식을 해볼까요 ?
public class StarbuzzCoffee {
public static void main(String args[]) {
Beverage beverage = new DarkRoast();
beverage = new Mocha(beverage);
beverage = new Whip(beverage);
System.out.println(beverage.getDescription()
+ " $" + beverage.cost());
}
}
실행 결과는 어떨까요?
Dark Roast Coffee, Mocha, Whip $1.29