2008년 01월 28일
Decorator Pattern (데코레이터 패턴)

1. 상황

커피숍에서 판매되는 커피들을 주문하는 시스템을 만들려고 한다.
단순하게 위에 맞는 시스템의 그림을 한번 그려보자.














커피들은 기본 종류에서 휘핑크림이나, 모카, 우유등의 부가적인 맛도 첨가해야 한다.
그렇다면 Beverage 클래스의 서브클래스들이 수도없이 생성될 것이다.
이에 대한 해결책이 Decorator Pattern에서 제시한다.

2. 해결방안

위의 문제점을 상기해서 만약 우유 가격이나 휘핑크림이 인상되었다면 어떻게 될까.
우유나, 휘핑크림을 얹은 커피들을 어렵게 뒤져 수정해 줘야할 것이다.

상속을 써서 음료가격과 첨가물가격을 합한 총 가격을 계산하는 방법은 그리 좋은 방법이 되지 못했습니다.
클래스가 많아지거나 일부 서브클래스에는 적합하지 않은 기능을 베이스 클래스에 추가하게 되는 문제가 발생합니다.

우리가 대신 사용할 방법은 다음과 같습니다.
특정 커피에서 시작해서 첨가물로 그 음료를 decorate(장식) 하는 겁니다.
예를들어 어떤손님이 모카하고 휘핑크림을 추가한 다크로스트 커피를 주문한다면 다음과 같은 식으로
할 수 있을 것입니다.

- DarkRoast 객체를 가져온다.
- Mocha 객체로 장식한다.
- Whip 객체로 장식한다.
- cost() 메소드를 호출한다. 이때 첨가물의 가격을 계산하는 일은 해당 객체들에게 위임된다.

Decorator Pattern의 일반적인 정의는 다음과 같다.

























Decorator Pattern에서는 객체에 추가적인 요건을 동적으로 첨가한다.
데코레이터는 서브클래스를 만드는 것을 통해서 기능을 유연하게 확장할 수 있는 방법을 제공한다.

ConcreteComponent에 새로운 행동을 동적으로 추가하게 되고, ConcreteDecoratorA, ConcreteDecoratorB 안에는
Component객체가 있는데 이는 장식하고(Decorate) 있는 것을 위한 인스턴스 Component에 대한 변수가 있다.

커피 주문에 대한 시스템을 위의 패턴으로 적용해 보면.































public abstract class Beverage {

 String description = "제목 없음";

 public String getDescription() {
  return description;
 }

 public abstract double cost();

}

public class HouseBlend extends Beverage {

 public HouseBlend(){
  
  description = "하우스블렌드";
 }
 public double cost() {
  return 2.50;
 }
}

public class Mocha extends CondimentDecorator {

 Beverage beverage;
 
 public Mocha(Beverage beverage) {
  this.beverage = beverage;
 }
 
 
 public double cost() {
  return .20 + beverage.cost();
 }


 public String getDescription() {
  return beverage.getDescription() + ", 모카";
 }

}

public class Milk extends CondimentDecorator {

 Beverage beverage;
 
 public Milk(Beverage beverage) {
  this.beverage = beverage;
 }
 
 
 public double cost() {
  return .40 + beverage.cost();
 }


 public String getDescription() {
  return beverage.getDescription() + ", 우유";
 }

}

public class DecoratorClient {

 /**
  * @param args
  */
 public static void main(String[] args) {
  
  // 순수한 하우스블렌드
  Beverage beverage = new HouseBlend();
  System.out.println(beverage.getDescription() + " $"+beverage.cost());
  
  // 모카를 추가한다.(장식한다) --> 하우스블렌드 모카
  Beverage beverage2 = new Mocha(beverage);
  System.out.println(beverage2.getDescription() + " $"+beverage2.cost());
  
  // 우유를 추가한다. --> 하우스블렌드 모카 우유
  Beverage beverage3 = new Milk(beverage2);
  System.out.println(beverage3.getDescription() + " $"+beverage3.cost());
 }

}


--> 결과 값

하우스블렌드 $2.5
하우스블렌드, 모카 $2.7
하우스블렌드, 모카, 우유 $3.1


by 씨부렁할매 | 2008/01/28 16:26 | design pattern | 트랙백(1) | 덧글(0)
트랙백 주소 : http://bowie.egloos.com/tb/1348409
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
Tracked from 마인드맵 활용 가이드-.. at 2008/08/03 13:19

제목 : 마인드맵 정리 - 데코레이터 패턴 (Decorato..
데코레이터 패턴 (Decorator Pattern) 신입 바리스타 훈련을 예로 드는 군요.. "라떼 추가하고 휘핑 크림을 얹은 더블 모카" 주문이 들어오면 어떻게 할까요? 카라멜 추가? 첨가물의 가격이 바뀔 때 마다 기존 코드를 수정해야 한다.(OpenClosePre.. 원리를 위배함) 첨가물의 종류가 추가 되면 새로운 함수를 추가해야 하고, cost() 함수도 추가해야 한다. 첨가물이 들어가면 안되는 Tea 서브 클래스에서도 has whip과......more

:         :

:

비공개 덧글



<< 이전 페이지 | 다음 페이지 >>