기존 객체 수정 없이 새로운 책임(기능)을 동적으로 추가하고 싶을때 사용하는 구조패턴
- Component : 실질적인 인스턴스를 컨트롤하는 역할
- ConcreteComponent : Component의 실질적인 인스턴스의 부분으로 책임의 주체의 역할
- Decorator : Component와 ConcreteDecorator를 동일시 하도록 해주는 역할
- ConcreteDecoreator : 실질적인 장식 인스턴스 및 정의이며 추가된 책임의 주체
카페 음료를 만들 때마다 매번 해당하는 클래스들의 객체를 생성해 주어야 하는 문제가 있을 수 있습니다. 이를 해결하기 위해 카페 음료의 기본 재료인 에스프레소라는 틀을 추상적으로 가지고 카페 음료를 만들 때 들어가는 재료들로 장식하는 방식을 사용하는 것입니다.
[Beverage.java]
public interface Beverage {
String getName();
int getPrice();
String add();
default void printPrice() {
System.out.println("가격 " + getPrice() + "원");
}
}
[Espresso.java]
public class Espresso implements Beverage {
@Override
public String getName() {
return "에스프레소";
}
@Override
public int getPrice() {
return 2000;
}
@Override
public String add() {
return getName();
}
}
[Decorator.java]
abstract public class Decorator implements Beverage {
private final Beverage beverage;
public Decorator(Beverage beverage) {
this.beverage = beverage;
}
@Override
public String add() {
return beverage.add();
}
@Override
public int getPrice() {
return beverage.getPrice();
}
}
[Water.java]
public class Water extends Decorator {
public Water(Beverage beverage) {
super(beverage);
}
@Override
public String getName() {
return "물";
}
@Override
public int getPrice() {
return super.getPrice() + 500;
}
@Override
public String add() {
return super.add() + " + " +getName();
}
}
[Milk.java]
public class Milk extends Decorator {
public Milk(Beverage beverage) {
super(beverage);
}
@Override
public String getName() {
return "우유";
}
@Override
public int getPrice() {
return super.getPrice() + 1000;
}
@Override
public String add() {
return super.add() + " + " + getName();
}
}
[Syrup.java]
public class Syrup extends Decorator {
public Syrup(Beverage beverage) {
super(beverage);
}
@Override
public String getName() {
return "시럽";
}
@Override
public int getPrice() {
return super.getPrice() + 500;
}
@Override
public String add() {
return super.add() + " + " +getName();
}
}
[BackStar.java]
public class BackStar {
public static void main(String[] args) {
Beverage espresso = new Espresso();
System.out.println("에스프레소 : " + espresso.add());
espresso.printPrice();
Beverage americano = new Water(espresso);
System.out.println("아메리카노 : " + americano.add());
americano.printPrice();
Beverage caffeLatte = new Milk(espresso);
System.out.println("카페라떼 : " + caffeLatte.add());
caffeLatte.printPrice();
Beverage chocoLatte = new Milk(espresso);
chocoLatte = new Syrup(chocoLatte);
System.out.println("초코라떼 : " + chocoLatte.add());
chocoLatte.printPrice();
}
}
장점
- 객체에 동적으로 기능 추가가 간단하게 가능하다.
단점
- 데코레이터 클래스가 계속 추가되어 클래스가 많아질 수 있다.
- 껍질로 감싸는 형식이기 때문에 객체의 정체를 알기 힘들고 복잡해 질 수 있다.