알림 관련 라이브러리를 생각해보자. 처음에는 알림 클래스가 간단하게 구성되어 있을 것이다. 해당 알림 클래스는 중요한 이벤트가 발생할 때마다 사용자에게 알림을 보내는 역할을 한다.
하지만 나중에 facebook이나 slack 같은 어플리케이션에 알림을 보내려고 하면, 추가로 다른 알림 클래스를 생성하여, 기존 클래스를 상속받아야 한다.
그리고 한 번에 여러 어플리케이션에 알림을 보내려고 하면 각 알림 클래스들을 결합시킨 클래스를 새로 생성해야한다.
BaseDecorator
가 Wrapper 클래스Component
인터페이스로 선언한다.// Component
public interface Coffee {
void addTopping();
}
ConcreteComponent
클래스(Americano
)를 생성하고, Component
인터페이스(Coffee
)를 상속받아 공통된 행위를 클래스에 맞게 구현한다.ConcreteComponent
: wrapped 될 객체의 클래스// Concrete Component
public class Americano implements Coffee {
@Override
public void addTopping() {
System.out.println("아메리카노 추가");
}
}
BaseDecorator
클래스(CoffeeDecorator
)를 생성하고, wrapped된 객체의 참조를 저장하는 private
필드(보통 wrappee
라 함)를 생성한다. 해당 필드는 ConcreteComponent
와 연결될 수 있도록 Component
인터페이스 타입으로 생성되어야 한다. 그 후, Component
인터페이스의 메소드를 모두 구현한다.// Base Decorator
public class CoffeeDecorator implements Coffee {
private final Coffee wrappee;
CoffeeDecorator(Coffee coffee) {
this.wrappee = coffee;
}
@Override
public void addTopping() {
wrappee.addTopping();
}
}
BaseDecorator
클래스를 상속받는 ConcreteDecorator
클래스(JavaChipDecorator
, CoffeeDecorator
, MilkDecorator
)를 생성한다.// Concrete Decorator
public class JavaChipDecorator extends CoffeeDecorator{
public JavaChipDecorator(Coffee coffee) {
super(coffee);
}
@Override
public void addTopping() {
super.addTopping();
System.out.println("자바칩 추가");
}
}
public class MilkDecorator extends CoffeeDecorator{
public MilkDecorator(Coffee coffee) {
super(coffee);
}
@Override
public void addTopping() {
super.addTopping();
System.out.println("우유 추가");
}
}
public class WhippingCreamDecorator extends CoffeeDecorator{
public WhippingCreamDecorator(Coffee coffee) {
super(coffee);
}
@Override
public void addTopping() {
super.addTopping();
System.out.println("휘핑크림 추가");
}
}
Client
코드를 작성한다.public class Client {
public static void main(String[] args) {
// 아메리카노 추가
new Americano().addTopping();
// 아메리카노 추가
// 우유 추가
new MilkDecorator(
new Americano()
).addTopping();
// 아메리카노 추가
// 우유 추가
// 자바칩 추가
// 휘핑크림 추가
new WhippingCreamDecorator(
new JavaChipDecorator(
new MilkDecorator(
new Americano()
)
)
).addTopping();
}
}