🚀 데코레이터 패턴이란?
- 객체에 추가 요소를 동적으로 더할 수 있는 패턴
- 데코레이터를 사용하면 서브클래스를 만들 때보다 훨씬 유연하게 기능을 확장할 수 있음
위 그림에서는 구성 요소의 형식으로 Component를 추상 클래스로 만들었는데, 데코레이터 패턴에서는 특정한 추상 구성 요소를 지정하지 않기 때문에 인터페이스를 사용해도 된다. 따라서 기존의 코드 구조가 추상 클래스면 추상 클래스로 진행하고, 아니라면 인터페이스로 만들면 된다. 여기서는 추상 클래스로 생각하고 진행하겠다.
✏️ Component
- 기본 기능을 뜻하는 추상 클래스 or 인터페이스
- 데코레이터들은 이 클래스를 상속하고 있기에 서로를 감쌀 수 있음
✏️ ConcreteComponent
- 기본 기능(Component)을 구현(정의)하는 클래스
✏️ Decorator
- Component를 상속한 클래스들을 장식하는 기능에 대한 인터페이스 or 추상클래스
- 데코레이터에는 구성 요소(Component)의 레퍼런스를 포함한 인스턴스 변수가 있음
- 데코레이터는 자신이 장식할 구성 요소와 같은 인터페이스 또는 추상 클래스 상속
✏️ ConcreteDecoratorA, ConcreteDecoratorB
- 데코레이터는 Component 상태를 확장할 수 있음 (Component에 동적으로 추가될 수 있는 추가 행동을 정의)
- 데코레이터가 감싸고 있는 Component 객체용 인스턴스 변수가 있음
- 데코레이터가 새로운 메서드를 추가할 수 있지만, 일반적으로 Component에 있던 메서드를 별도의 작업으로 처리해서 새로운 기능을 추가함
🚀 예시 코드 작성해보기
커피 주문 서비스를 위해 커피를 데코레이터 패턴으로 만들어보자
- 커피 종류마다 구성 요소를 나타내는 구상 클래스 (HouseBlend, Decaf, Espresso)
- 각각의 추가 요소를 나타내는 데코레이터 (Milk, Mocha, Whip)
- 데코레이터 패턴은 데코레이터로 감싸는 객체의 형식과 같으므로 CondimentDecorator가 Beverage를 상속받음
- 구성 요소가 들어갈 자리에 자기가 들어갈 수 있어야하기 때문
✏️ Beverage 추상 클래스
public abstract class Beverage {
String description;
public String getDescription() {
return description;
}
public abstract int cost();
}
✏️ Espresso 구현 클래스
public class Espresso extends Beverage {
public Espresso() {
description = "에스프레소";
}
@Override
public int cost() {
return 1000;
}
}
- description은 Beverage로부터 상속받는 인스턴스 변수
- 구현 클래스에서는 cost()를 구현해줌
- 나머지 HouseBlend와 Decaf 클래스도 동일
✏️ CondimentDecorator 추상 클래스
public abstract class CondimentDecorator extends Beverage {
Beverage beverage;
public abstract String getDescription();
}
- 각 데코레이터가 감쌀 음료를 나타내는 Beverage 객체를 인스턴수 변수인 beverage에 저장
- 커피를 지정할 때는 데코레이터에서 어떤 커피든 감쌀 수 있도록 Beverage 슈퍼클래스 사용
- 모든 추가 요소 데코레이터에 getDescription()을 새로 구현하도록 만들기 위해 추상 메서드 추가
✏️ Mocha 구현 클래스
public class Mocha extends CondimentDecorator {
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
@Override
public int cost() {
return beverage.cost() + 500;
}
@Override
public String getDescription() {
return beverage.getDescription() + ", 모카";
}
}
- Mocha 생성자는 Beverage 레퍼런스가 들어와있음
- 이 데코레이터는 커피에서 추가적으로 넣는 요소이기 때문
- cost()에는 커피 가격에 모카를 추가한 가격을 구현
- getDescription()에는 커피 이름과 아이템 이름도 같이 구현
✏️ 테스트해보기
Beverage espresso = new Espresso();
System.out.println(espresso.getDescription() + " : " + espresso.cost());
// 에스프레소 : 1000
Beverage decaf = new Decaf();
decaf = new Mocha(decaf);
decaf = new Whip(decaf);
System.out.println(decaf.getDescription() + " : " + decaf.cost());
// 디카페인, 모카, 휘핑 : 2500
Beverage houseBlend = new HouseBlend();
houseBlend = new Milk(houseBlend);
houseBlend = new Milk(houseBlend);
houseBlend = new Whip(houseBlend);
System.out.println(houseBlend.getDescription() + " : " + houseBlend.cost());
// 하우스 블렌드 커피, 우유, 우유, 휘핑 : 3000
위 코드는 여기를 클릭하면 나옴
https://gmlwjd9405.github.io/2018/07/09/decorator-pattern.html
'프로그래밍 > 디자인패턴' 카테고리의 다른 글
Observer(옵저버) 패턴이란? (0) | 2023.03.30 |
---|---|
Strategy Pattern(전략 패턴)이란? (0) | 2023.03.21 |
Delegate Pattern(델리게이트 패턴, 위임 패턴)이란? (1) | 2023.03.15 |