// 1. 기본 컴포넌트 (인터페이스)
interface Coffee {
String getDescription();
double getCost();
}
// 2. 기본 커피 클래스
class BasicCoffee implements Coffee {
public String getDescription() {
return "기본 커피";
}
public double getCost() {
return 3000;
}
}
// 3. 데코레이터 (추상 클래스)
abstract class CoffeeDecorator implements Coffee {
protected Coffee decoratedCoffee;
public CoffeeDecorator(Coffee coffee) {
this.decoratedCoffee = coffee;
}
public String getDescription() {
return decoratedCoffee.getDescription();
}
public double getCost() {
return decoratedCoffee.getCost();
}
}
// 4. 추가 기능: 우유 추가
class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) {
super(coffee);
}
public String getDescription() {
return super.getDescription() + ", 우유 추가";
}
public double getCost() {
return super.getCost() + 500;
}
}
// 5. 추가 기능: 시럽 추가
class SyrupDecorator extends CoffeeDecorator {
public SyrupDecorator(Coffee coffee) {
super(coffee);
}
public String getDescription() {
return super.getDescription() + ", 시럽 추가";
}
public double getCost() {
return super.getCost() + 300;
}
}
// 6. 사용 예
public class Main {
public static void main(String[] args) {
Coffee coffee = new BasicCoffee(); // 기본 커피
coffee = new MilkDecorator(coffee); // 우유 추가
coffee = new SyrupDecorator(coffee); // 시럽 추가
System.out.println(coffee.getDescription() + " 가격: " + coffee.getCost() + "원");
}
}
✅ 장점 • 기존 코드를 수정하지 않고 기능 확장 가능 (OCP 준수) • 객체 간 조합을 통해 다양한 기능을 동적으로 추가 가능 • 상속보다 유연한 설계 가능
❌ 단점 • 데코레이터가 많아지면 구조가 복잡해질 수 있음 • 객체가 여러 개 감싸지는 방식이라 디버깅이 어려울 수 있음