데코레이터 패턴은 객체지향 설계에서 사용되는 구조적 디자인 패턴 중 하나로, 기존 객체에 새로운 책임(behavior)을 동적으로 추가하고자 할 때 사용된다. 이 패턴은 서브클래싱을 통한 기능 확장의 한계를 극복하기 위해, 동일한 인터페이스를 구현하거나 상속받은 ‘데코레이터’ 객체가 원래 객체를 감싸서 추가 기능을 제공한다.
주요 목적
- 확장성: 런타임 시점에 객체에 행위를 추가하거나 제거할 수 있다.
- 유연성: 여러 개의 데코레이터를 조합하여 복합적인 기능을 구성할 수 있다.
- 단일 책임 원칙(SRP): 각각의 데코레이터가 하나의 책임만을 담당하도록 설계한다.
구조 (UML 요소)
| 요소 | 역할 |
|---|---|
| Component (추상 클래스/인터페이스) | 데코레이터와 구체 객체가 구현해야 할 인터페이스 정의 |
| ConcreteComponent | 기본 기능을 제공하는 구체 클래스 |
| Decorator (추상 클래스) | Component 인터페이스를 구현하고, 내부에 Component 객체에 대한 참조를 유지 |
| ConcreteDecorator | Decorator를 상속받아 구체적인 부가 기능을 구현 |
동작 흐름
- 클라이언트는
Component타입의 객체를 생성한다 (ConcreteComponent). - 추가 기능이 필요하면
ConcreteDecorator객체를 생성하고, 기존Component객체를 인자로 전달한다. - 클라이언트는 데코레이터 객체를
Component타입으로 사용한다. 호출은 데코레이터를 통해 원래 객체에 전파되며, 데코레이터는 자체 로직을 수행한 뒤 원래 객체의 메서드를 호출한다.
사용 예시 (Java)
// Component
public interface Coffee {
double cost();
}
// ConcreteComponent
public class SimpleCoffee implements Coffee {
@Override
public double cost() {
return 2.0;
}
}
// Decorator
public abstract class CoffeeDecorator implements Coffee {
protected final Coffee coffee;
public CoffeeDecorator(Coffee coffee) {
this.coffee = coffee;
}
}
// ConcreteDecorator
public class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) {
super(coffee);
}
@Override
public double cost() {
return coffee.cost() + 0.5; // 우유 추가 비용
}
}
// 클라이언트
Coffee myCoffee = new MilkDecorator(new SimpleCoffee());
System.out.println(myCoffee.cost()); // 2.5
장점
- 동적 확장: 실행 중에 객체의 기능을 자유롭게 조합·제거 가능.
- 클래스 폭발 방지: 기능 조합을 위한 서브클래스를 미리 정의할 필요가 없어 클래스 수가 급증하지 않는다.
- 투명성: 클라이언트는 데코레이터와 원래 객체를 동일하게 취급한다.
단점
- 디버깅 난이도: 여러 데코레이터가 중첩될 경우 호출 흐름 파악이 어려울 수 있다.
- 설계 복잡성: 구조가 과도하게 얽히면 유지보수가 힘들어질 위험이 있다.
관련 패턴
- 프록시(Proxy) 패턴: 객체에 대한 접근 제어 및 추가 작업을 수행하지만, 데코레이터는 기능 확장에 초점을 맞춘다.
- 어댑터(Adapter) 패턴: 인터페이스 호환성을 위해 변환한다는 점에서 차이가 있다.
- 컴포지트(Composite) 패턴: 트리 구조의 객체들을 동일하게 다루지만, 데코레이터는 동일 인터페이스를 유지하면서 기능을 부가한다.
요약
데코레이터 패턴은 객체에 새로운 책임을 동적으로 부여하기 위해 기존 객체를 감싸는 구조를 제공한다. 이를 통해 서브클래싱 없이도 다양한 기능을 조합·확장할 수 있으며, 객체지향 설계 원칙 중 개방-폐쇄 원칙(OCP)과 단일 책임 원칙을 효과적으로 지원한다.