JAVA設計模式之裝飾者模式

咖啡店須要作一個訂單系統,以合乎飲料供應要求。java

1.最初是這樣設計的:ide

 1 /**
 2  * 飲料抽象類
 3  *
 4  */
 5 public abstract class Beverage {
 6     
 7     protected String description;
 8     
 9     public String getDescription() {
10         return this.description;
11     }
12     
13     /**
14      * 子類需自定義本身的價格
15      * @return
16      */
17     public abstract double cost();
18     
19 }

每一種飲料都須要繼承該抽象類,並覆寫cost()方法。測試

2.可是購買咖啡時須要考慮到調料的部分,每種咖啡會加不一樣種的調料,好比蒸奶、豆漿、摩卡或者覆蓋奶泡,那麼訂單系統須要考慮加入不一樣調料後的價格。所以須要實現不一樣的子類來定義添加不一樣調料後的價格。你們知道,一種咖啡跟多種調料有多種組合方式,那麼多種咖啡和多種調料的組合後,幾乎是類爆炸!this

 

維護極其困難:spa

若是某種飲料價格調整;或是新增了某種飲料,怎麼辦?設計

 

後來通過改進後,把是否存在某種調料做爲飲料的屬性,並在飲料抽象類中實現cost方法,子類能夠覆寫cost方法並設置添加的調料最終肯定添加不一樣調料後的價格:code

 1 /**
 2  * 飲料抽象類
 3  *
 4  */
 5 public abstract class Beverage {
 6     
 7     private boolean milk;//牛奶
 8     private boolean soy;//豆漿
 9     private boolean mocha;//摩卡
10     private boolean whip;//奶泡
11     
12     private double milkCost = 0.19;
13     private double soyCost = 0.26;
14     private double mochaCost = 0.29;
15     private double whipCost = 0.17;
16     
17     protected String description;
18     
19     //setter getter method
20 
21     public String getDescription() {
22         return this.description;
23     }
24     
25     public double cost() {
26         double condimentCost = 0.0;
27         if (hasMilk()) {
28             condimentCost += milkCost;
29         }
30         if (hasSoy()) {
31             condimentCost += soyCost;
32         }
33         if (hasMocha()) {
34             condimentCost += mochaCost;
35         }
36         if (hasWhip()) {
37             condimentCost += whipCost;
38         }
39         return condimentCost;
40     }
41     
42 }
43 
44 /**
45  * 低糖咖啡
46  *
47  */
48 public class Decaf extends Beverage {
49     
50     @Override
51     public String getDescription() {
52         return "It is Decaf.";
53     }
54 
55     @Override
56     public double cost() {
57         super.setMilk(true);//添加牛奶調料
58         return 1.99 + super.cost();
59     }
60     
61 }

這樣一來,若是有五種咖啡,那麼只須要實現五個子類便可,不一樣的子類能夠靈活設置添加不一樣的調料。對象

可是這樣的設計存在必定的問題:blog

1)調料價格的改變會使咱們改變現有代碼;繼承

2)出現新調料,就須要加上新的方法,並改變父類中的cost方法;

3)若出現新的飲料,如紅茶,那麼新的飲料繼承該父類,父類中的調料屬性並不合適,如奶泡等;

... ...

 

設計原則:類應該對擴展開放,對修改關閉。

 

裝飾者模式思想:以飲料爲主體,而後在運行時以調料來「裝飾」飲料。

例如客戶須要摩卡和奶泡深焙咖啡,那麼要作的是:

拿一個深焙咖啡對象;

以摩卡對象裝飾;

以奶泡對象裝飾;

摩卡和奶泡屬於調料,可是也是裝飾者,它的類型反映了它裝飾的對象,所謂反映,指的是二者類型一致。那麼全部調料須要繼承Beverage。

 

使用裝飾者模式設計的代碼:

 1 /**
 2  * 飲料抽象類
 3  *
 4  */
 5 public abstract class Beverage {
 6     
 7     protected String description;
 8     
 9     public String getDescription() {
10         return this.description;
11     }
12     
13     /**
14      * 獲取每種飲料的價格
15      * @return
16      */
17     public abstract double cost();
18 }
19 
20 /**
21  * 調料抽象類
22  *
23  */
24 public abstract class Condiment extends Beverage {
25     
26     public abstract String getDescription();
27     
28 }

這裏調料繼承飲料,僅僅是爲了使二者具備相同的類型,並不是爲了複用父類的行爲。

下面是飲料的子類:

 1 /**
 2  * 深焙咖啡
 3  *
 4  */
 5 public class DarkRoast extends Beverage {
 6     
 7     public DarkRoast() {
 8         description = "DarkRoast";
 9     }
10     @Override
11     public double cost() {
12         return 0.19;
13     }
14 
15 }
16 
17 /**
18  * 濃縮咖啡
19  *
20  */
21 public class Espresso extends Beverage {
22     
23     public Espresso() {
24         description = "Espresso";
25     }
26     
27     @Override
28     public double cost() {
29         return 1.99;
30     }
31 
32 }
33 
34 /**
35  * 黑咖啡
36  *
37  */
38 public class HoseBlend extends Beverage {
39     
40     public HoseBlend() {
41         description = "Hose Blend Coffee";
42     }
43     
44     @Override
45     public double cost() {
46         return 0.99;
47     }
48 
49 }

調料(裝飾者)子類:

 1 /**
 2  * 摩卡
 3  *
 4  */
 5 public class Mocha extends Condiment {
 6 
 7     private Beverage beverage;
 8     
 9     public Mocha(Beverage beverage) {
10         this.beverage = beverage;
11     }
12 
13     @Override
14     public String getDescription() {
15         return beverage.getDescription() + ", Mocha";
16     }
17 
18     @Override
19     public double cost() {
20         return 0.20 + beverage.cost();
21     }
22 
23 }
24 
25 /**
26  * 豆漿
27  *
28  */
29 public class Soy extends Condiment {
30     
31     private Beverage beverage;
32     
33     public Soy(Beverage beverage) {
34         this.beverage = beverage;
35     }
36 
37     @Override
38     public String getDescription() {
39         return beverage.getDescription() + ", Soy";
40     }
41 
42     @Override
43     public double cost() {
44         return 0.23 + beverage.cost();
45     }
46 
47 }
48 
49 /**
50  * 奶泡
51  *
52  */
53 public class Whip extends Condiment {
54     
55     private Beverage beverage;
56     
57     public Whip(Beverage beverage) {
58         this.beverage = beverage;
59     }
60     
61     @Override
62     public String getDescription() {
63         return beverage.getDescription() + ", Whip";
64     }
65 
66     @Override
67     public double cost() {
68         return 0.69 + beverage.cost();
69     }
70 
71 }

測試代碼:

 1 public class ComponentTest {
 2     @Test
 3     public void test() {
 4         Beverage beverage = new Espresso();
 5         System.out.println(beverage.getDescription() + ", $" + beverage.cost());
 6         Beverage beverage2 = new HoseBlend();
 7         beverage2 = new Mocha(beverage2);
 8         beverage2 = new Mocha(beverage2);
 9         beverage2 = new Whip(beverage2);
10         System.out.println(beverage2.getDescription() + ", $" + beverage2.cost());
11         Beverage beverage3 = new DarkRoast();
12         beverage3 = new Soy(beverage3);
13         beverage3 = new Mocha(beverage3);
14         beverage3 = new Whip(beverage3);
15         System.out.println(beverage3.getDescription() + ", $" + beverage3.cost());
16     }
17 }

運行結果:

1 Espresso, $1.99
2 Hose Blend Coffee, Mocha, Mocha, Whip, $2.08
3 DarkRoast, Soy, Mocha, Whip, $1.31

 

java/IO中有不少用到裝飾者模式的設計,有興趣的朋友能夠了解下。

相關文章
相關標籤/搜索