Decorator Pattern
- 자바의 입출력 스트림은 decorater pattern으로 구현됨
- 상속보다 유연한 구현 방식
- 지속적인 기능의 추가와 제거가 용이함
- 데코레이터는 컴포넌트 또는 또 다른 데코레이터를 포함해야 함
- 여러 데코레이터로 다양한 기능을 추가할 수 있음
- Component : 실제로 I/O를 할 수 있는 오브젝트
- Decorator : 추가적인 기능을 제공
- ConcreteComponent와 Decorator는 Component로부터 상속을 받음
- 클래스 다이어그램

- ConcreteComponent와 Decorator는 Component로부터 상속을 받음
- Operation()은 ConcreteComponent에서 최종 수행
예제 코드
Decorator Pattern을 활용하여 커피샵 메뉴 구현하기
에스프레소에는 에티오피아와 케냐 두가지 종류가 있고,
에스프레소에 물을 추가하면 아메리카노,
우유를 추가하면 라떼가 제조된다.
이때 기호에 따라 모카 시럽, 휘핑크림이 추가될 수 있다.
추가된 요소에 따라 가격을 다르게 계산한다.
에스프레소 1000원 / 아메리카노 2000원 / 라떼 3000원 / 모카시럽 + 500원 / 휘핑크림 + 500원
Coffee.java
- Component
- 추상 클래스로 하위 클래스가 구현할 기능을 추상 메서드로 구현함
package coffeeshop;
public abstract class Coffee {
public abstract int cost();
public abstract void brew();
}
Espresso.java
- Coffee 하위에 추상 클래스를 만들어 공통으로 제공할 기능을 구현
package coffeeshop;
public abstract class Espresso extends Coffee{
@Override
public int cost() { // 에스프레소 공통 가격
return 1000;
}
}
Ethiopia.java
- ConcreteComponent
- Component에 선언된 메서드 중 구현되지 않은 메서드를 구현함
package coffeeshop;
public class Ethiopia extends Espresso{
@Override
public void brew() {
System.out.print("Ethiopia Espresso");
}
}
Decorator.java
- Decorator
- Component인 Coffee를 상속받음
- 오로지 상속을 위한 클래스로 단독으로 사용될 일이 없기 때문에 추상 클래스로 선언함
- Coffee의 객체를 매개변수로 받는 생성자를 만들어 Coffee로부터 상속받은 객체들을 입력받고 Wrapper Class의 역할을 함
- 추상 메서드는 매개변수로 들어온 객체의 메서드 호출하여 구현함
package coffeeshop;
public abstract class Decorator extends Coffee{
Coffee coffee;
public Decorator(Coffee coffee) {
this.coffee = coffee;
}
@Override
public int cost() {
return coffee.cost();
}
@Override
public void brew() {
coffee.brew();
}
}
Milk.java
- Decorator로부터 상속을 받음
- Decorator에 매개변수를 받는 생성자가 있기 때문에 하위 클래스에서도 똑같이 구현해주어야 함
- 각 메서드에서 상위 클래스의 메서드를 호출하고, 추가 기능을 더함
package coffeeshop;
public class Milk extends Decorator{
public Milk(Coffee coffee) {
super(coffee);
}
public void brew() {
super.brew();
System.out.print(" Adding Milk");
}
public int cost() {
return super.cost() + 2000;
}
}
CoffeeShop.java
package coffeeshop;
public class CoffeeShop {
public static void main(String[] args) {
Coffee ethEspresso = new Ethiopia(); // 에티오피아 에스프레소
ethEspresso.brew();
System.out.println(" 가격 : " + ethEspresso.cost() + "원");
System.out.println();
Coffee ehtAmericano = new Water(new Ethiopia()); // 에티오피아 아메리카노
ehtAmericano.brew();
System.out.println(" 가격 : " + ehtAmericano.cost() + "원");
System.out.println();
Coffee ethLatte = new Milk(new Ethiopia()); // 에티오피아 라떼
ethLatte.brew();
System.out.println(" 가격 : " + ethLatte.cost() + "원");
System.out.println();
Coffee kenWhippedMocha = new WhippedCream(new MochaSyrup(new Milk(new Kenya()))); // 휘핑크림 추가한 케냐 모카 라떼
kenWhippedMocha.brew();
System.out.println(" 가격 : " + kenWhippedMocha.cost() + "원");
}
}
수행 결과
Ethiopia Espresso 가격 : 1000원
Ethiopia Espresso Adding Water 가격 : 2000원
Ethiopia Espresso Adding Milk 가격 : 3000원
Kenya Espresso Adding Milk Adding Mocha Syrup Adding Whipped Cream 가격 : 4000원
'Java & Kotlin' 카테고리의 다른 글
[Java 기능] 쓰레드(Thread) (0) | 2022.02.18 |
---|---|
[Java 기능] 그외 여러가지 입출력 클래스들 (0) | 2022.02.17 |
[Java 기능] 직렬화 (0) | 2022.02.17 |