2014年9月17日 星期三

用 Decorator Pattern (裝飾者模式) 實作台式飲品店

參考書籍:
Head First Design Patterns (這是一本學Design Pattern 很好的書,漫畫形式,很易看易懂)
參考連結:
Wiki Decorator Pattern
神人對Decorator Pattern 的文章 (這篇文章好清楚,如果沒有書看這個也很簡單易明。)
簡單來說,如果有一些物件是同時有[相同特性]和[相似特性]時,就很適合用Decorator Pattern。
就舉台式飲品為例,各式台式飲品都有相同的特性,例如產品名稱、基本價格、等等。
也可以相似的特性,例如加各式配料,加珍珠、加仙草、等等
在這個例子,相同的特性就放在Component 去實現,相似特性就放到Decorator 去實現。
Component 的抽象類別,將相同的特性如產品名稱、基本價格都放在這裡:
package decorator.beverage;

public abstract class Beverage {
 
 String description = "Unknown Beverage";
 
 public String getDescription(){
  return description;
 }
 
 public abstract double cost();

}

Component 的實作,假設我們的小店只有奶茶和奶綠兩種飲品:
package decorator.beverage;

public class MilkTea extends Beverage {
 
 // override the abstract class description
 public MilkTea(){
  description = "Milk Tea";
 }
 
 // implement the abstract method
 public double cost() {
  return 1.99;
 }

}
package decorator.beverage;

public class MilkGreenTea extends Beverage {

 // override the abstract class description
 public MilkGreenTea(){
  description = "Milk GreenTea";
 }

 // implement the abstract method
 public double cost() {
  return 2.99;
 }

}

然後就是Decroator 的抽象類別:
package decorator.beverage.flavouring;

import decorator.beverage.Beverage;

public abstract class FlavouringDecorator extends Beverage {

 // Decorator should reimplement this to decorate the beverage
 public abstract String getDescription(); 

}

然後是Decorator 的實作,假設我們有三種Decorator,冰的、加珍珠、加仙草:
package decorator.beverage.flavouring;

import decorator.beverage.Beverage;

public class Iced extends FlavouringDecorator {

 Beverage drink;
 
 //Decorator must have the base beverage
 public Iced(Beverage drink){
  this.drink = drink;
 }
 
 // Decorate the description of the beverage
 public String getDescription() {
  return "Iced " + drink.getDescription();
 }

 // Add the cost of Jelly to the beverage
 public double cost() {
  return drink.cost() + 0.20;
 }

}
package decorator.beverage.flavouring;

import decorator.beverage.Beverage;

public class Pearl extends FlavouringDecorator {

 Beverage drink;
 
 //Decorator must have the base beverage
 public Pearl(Beverage drink){
  this.drink = drink;
 }
 
 // Decorate the description of the beverage
 public String getDescription() {
  return drink.getDescription() + ", with Pearl";
 }

 // Add the cost of pearl to the beverage
 public double cost() {
  return drink.cost() + 0.5;
 }

}
package decorator.beverage.flavouring;

import decorator.beverage.Beverage;

public class Jelly extends FlavouringDecorator {

 Beverage drink;
 
 //Decorator must have the base beverage
 public Jelly(Beverage drink){
  this.drink = drink;
 }
 
 // Decorate the description of the beverage
 public String getDescription() {
  return drink.getDescription() + ", with Jelly";
 }

 // Add the cost of Jelly to the beverage
 public double cost() {
  return drink.cost() + 0.70;
 }

}

最後就是我們的小店貢X開店了,我們點了三種飲品,分別是凍仙草奶茶、珍珠奶綠、凍珍珠奶茶......
package decorator;

import decorator.beverage.*;

public class GongTea {

 public static void main(String[] args) {
  
  //凍仙草奶茶
  Beverage beverage1 = new MilkTea();
  beverage1 = new Iced(beverage1);
  beverage1 = new Jelly(beverage1);
  System.out.println("Beverage1 is " + beverage1.getDescription() + ", price is $" + beverage1.cost());
  
  //珍珠奶綠
  Beverage beverage2 = new MilkGreenTea();
  beverage2 = new Pearl(beverage2);
  System.out.println("Beverage2 is " + beverage2.getDescription() + ", price is $" + beverage2.cost());
  
  //凍珍珠奶茶
  Beverage beverage3 = new MilkTea();
  beverage3 = new Iced(beverage3);
  beverage3 = new Pearl(beverage3);
  System.out.println("Beverage3 is " + beverage3.getDescription() + ", price is $" + beverage3.cost());
  
 }

}

運行的結果如下:
DecoratorTestingOutput

沒有留言:

張貼留言