1 星巴克咖啡訂單專案(咖啡館):
1) 咖啡種類/單品咖啡:Espresso(義大利濃咖啡)、ShortBlack、LongBlack(美式咖啡)、Decaf(無因咖啡)
2) 調料:Milk、Soy(豆漿)、Chocolate
3) 要求在擴充套件新的咖啡種類時,具有良好的擴充套件性、改動方便、維護方便
4) 使用 OO 的來計算不同種類咖啡的費用: 客戶可以點單品咖啡,也可以單品咖啡+調料組合。
2 方案 1-解決星巴克咖啡訂單專案
3 方案 1-解決星巴克咖啡訂單問題分析
1) Drink 是一個抽象類,表示飲料
2) des 就是對咖啡的描述, 比如咖啡的名字
3) cost() 方法就是計算費用,Drink 類中做成一個抽象方法.
4) Decaf 就是單品咖啡, 繼承 Drink, 並實現 cost
5) Espress && Milk 就是單品咖啡+調料, 這個組合很多
6) 問題:這樣設計,會有很多類,當我們增加一個單品咖啡,或者一個新的調料,類的數量就會倍增,就會出現類爆炸
4.1 方案 2-解決星巴克咖啡訂單(好點)
1) 前面分析到方案 1 因為咖啡單品+調料組合會造成類的倍增,因此可以做改進,將調料內建到 Drink 類,這樣就不會造成類數量過多。從而提高專案的維護性(如圖)
2) 說明: milk,soy,chocolate 可以設計為 Boolean,表示是否要新增相應的調料.
4 .2 方案 2-解決星巴克咖啡訂單問題分析
1) 方案 2 可以控制類的數量,不至於造成很多的類
2) 在增加或者刪除調料種類時,程式碼的維護量很大
3) 考慮到使用者可以新增多份 調料時,可以將 hasMilk 返回一個對應 int
4) 考慮使用 裝飾者 模式
5 裝飾者模式定義
1) 裝飾者模式:動態的將新功能附加到物件上。在物件功能擴充套件方面,它比繼承更有彈性,裝飾者模式也體現了開閉原則(ocp)
2) 這裡提到的動態的將新功能附加到物件和 ocp 原則,在後面的應用例項上會以程式碼的形式體現,請同學們注意體會。
6 裝飾者模式原理
1) 裝飾者模式就像打包一個快遞
主體:比如:陶瓷、衣服 (Component) // 被裝飾者
包裝:比如:報紙填充、塑料泡沫、紙板、木板(Decorator)
2) Component 主體:比如類似前面的 Drink
3) ConcreteComponent 和 Decorator
ConcreteComponent:具體的主體, 比如前面的各個單品咖啡
4) Decorator: 裝飾者,比如各調料.
在如圖的 Component 與 ConcreteComponent 之間,如果 ConcreteComponent 類很多,還可以設計一個緩衝層,
將共有的部分提取出來,抽象層一個類。
7 裝飾者模式解決星巴克咖啡訂單
8 裝飾者模式下的訂單:2 份巧克力+一份牛奶的 LongBlack
9 裝飾者模式咖啡訂單專案應用例項
Drink類
package com.lin.decorator; public abstract class Drink { public String des;//描述 private float price = 0.0f; public String getDes() { return des; } public void setDes(String des) { this.des = des; } public float getPrice() { return price; } public void setPrice(float price) { this.price = price; } public abstract float cost(); }
Espresso類
package com.lin.decorator; // 義大利Coffee public class Espresso extends Coffee { public Espresso() { super.setDes("義大利咖啡"); super.setPrice(16.01f); } }
LongBlack 類
package com.lin.decorator; public class LongBlack extends Coffee { public LongBlack() { super.setPrice(14.0f); super.setDes(getPrice()+"美國咖啡"); } }
Coffee類
package com.lin.decorator; public class Coffee extends Drink{ @Override public float cost() { return super.getPrice(); } }
Decorator 類
package com.lin.decorator; public class Decorator extends Drink{ private Drink obj; @Override public float cost() { return super.getPrice() + obj.cost(); } public Decorator(Drink obj) { this.obj = obj; } @Override public String getDes() { return super.getPrice() + " " + super.getDes() + "&&" + obj.getDes() ; } }
Chocolate 類
package com.lin.decorator; public class Chocolate extends Decorator{ public Chocolate(Drink obj) { super(obj); super.setDes("巧克力"); super.setPrice(3.0f); } } class Milk extends Decorator{ public Milk(Drink obj) { super(obj); super.setDes("牛奶"); super.setPrice(4.0f); } } class Sof extends Decorator{ public Sof(Drink obj) { super(obj); super.setDes("豆漿"); super.setPrice(1.0f); } }
CoffeeStore 類
package com.lin.decorator; public class CoffeeStore { /* * 2分巧克力+一份牛奶的LongBlack * 1 1份LongBlack * 2 1份牛奶 * 3 2份巧克力 */ public static void main(String[] args) { Drink longBlack = new LongBlack(); System.out.println("free:" + longBlack.cost()+"\t"+"des:"+longBlack.getDes()); longBlack = new Milk(longBlack); System.out.println("free:" + longBlack.cost()+"\t"+"des:"+longBlack.getDes()); longBlack = new Chocolate(longBlack); System.out.println("free:" + longBlack.cost()+"\t"+"des:"+longBlack.getDes()); longBlack = new Chocolate(longBlack); System.out.println("free:" + longBlack.cost()+"\t"+"des:"+longBlack.getDes()); } }
10 裝飾者模式在 JDK 應用的原始碼分析
1. InputStream 是抽象類, 類似我們前面講的 Drink
2. FileInputStream 是 InputStream 子類,類似我們前面的 DeCaf, LongBlack
3. FilterInputStream 是 InputStream 子類:類似我們前面 的 Decorator 修飾者
4. DataInputStream 是 FilterInputStream 子類,具體的修飾者,類似前面的 Milk, Soy 等
5. FilterInputStream 類 有 protected volatile InputStream in; 即含被裝飾者
6. 分析得出在 jdk 的 io 體系中,就是使用裝飾者模式
僅供參考,有錯誤還請指出!
有什麼想法,評論區留言,互相指教指教。