디코레이터 패턴 개요 디코레이터 패턴은 객체의 기능을 동적으로 확장할 수 있도록 하는 구조적 디자인 패턴입니다. 이 패턴은 기존 클래스를 수정하지 않고 추가적인 책임을 부여할 수 있는 메커니즘을 제공하며, 특히 단일 책임 원칙을 준수하는 시스템에서 유용하게 활용됩니다.
구성 요소
- 인터페이스: 기능 확장이 가능한 기본 객체 타입 정의
- 기본 클래스: 인터페이스를 구현한 기본 구현체
- 디코레이터 추상 클래스: 기본 객체를 감싸는 래퍼 클래스로, 동적 확장 기능 제공
- 구체적 디코레이터: 추가 기능을 구현한 실제 확장 클래스
실무 예시 다음은 음료 제작 시스템을 대상으로 한 예제입니다:
// 기본 인터페이스
public interface Drink {
double getPrice();
}
// 기본 구현체
public class BasicDrink implements Drink {
@Override
public double getPrice() {
return 8000; // 기본 가격 8,000원
}
}
// 디코레이터 추상 클래스
public abstract class DrinkDecorator implements Drink {
protected Drink wrappedDrink;
public DrinkDecorator(Drink drink) {
this.wrappedDrink = drink;
}
@Override
public double getPrice() {
return wrappedDrink.getPrice();
}
}
// 추가 기능 구현 클래스
public class MilkDecorator extends DrinkDecorator {
public MilkDecorator(Drink drink) {
super(drink);
}
@Override
public double getPrice() {
return super.getPrice() + 1500; // 우유 추가 1,500원
}
}
public class WhipDecorator extends DrinkDecorator {
public WhipDecorator(Drink drink) {
super(drink);
}
@Override
public double getPrice() {
return super.getPrice() + 1000; // 육류 추가 1,000원
}
}
사용 예제
public class DecoratorDemo {
public static void main(String[] args) {
Drink basic = new BasicDrink();
System.out.println("기본 음료 가격: " + basic.getPrice());
Drink milk = new MilkDecorator(basic);
System.out.println("우유 추가 음료 가격: " + milk.getPrice());
Drink whip = new WhipDecorator(milk);
System.out.println("육류 추가 음료 가격: " + whip.getPrice());
}
}
이 패턴은 여러 레イヤ를 중첩하여 기능을 조합할 수 있는 유연성을 제공합니다. 각 디코레이터는 자신만의 책임을 명확히 하며, 클라이언트는 필요한 기능만 순차적으로 적용할 수 있습니다. 이 방식은 코드 재사용성 향상과 열린/폐쇄 원칙을 준수하는 설계에 효과적입니다.