一、裝飾模式簡介
? ? ? ?裝飾模式(Decorator Pattern)是一種結構型設計模式,它允許向一個現有的對象添加新的功能,同時又不改變其結構。這種模式創建了一個裝飾類,用來包裝原有的類,并在保持類方法簽名完整性的前提下,提供了額外的功能。
二、星巴克咖啡系統設計
根據提供的UML類圖,我們來設計一個星巴克咖啡下單系統,該系統可以計算不同咖啡和調料組合的價格。
系統組成
-
抽象組件(Beverage):相當于Component類,是所有咖啡和調料的基類
-
具體組件:HouseBlend、Expresso、DarkRoast、Decaf,代表不同類型的咖啡
-
裝飾器(CondimentDecorator):抽象裝飾類
-
具體裝飾器:Milk、Mocha、Soy、Whip,代表不同的調料
三、代碼實現
1. 抽象組件(Beverage)
/*** 抽象組件 - 飲料基類* 相當于裝飾模式中的Component角色*/
public abstract class Beverage {// 飲料描述,初始為"Unknown Beverage"String description = "Unknown Beverage";/*** 獲取飲料描述* @return 飲料描述字符串*/public String getDescription() {return description;}/*** 計算飲料價格 - 抽象方法,由子類實現* @return 飲料價格*/public abstract double cost();
}
2. 具體組件(各種咖啡類型)
2.1 HouseBlend 咖啡
/*** 具體組件 - 混合咖啡*/
public class HouseBlend extends Beverage {public HouseBlend() {description = "House Blend Coffee";}@Overridepublic double cost() {return 0.89; // 基礎價格0.89美元}
}
2.2 Expresso 咖啡
/*** 具體組件 - 濃縮咖啡*/
public class Expresso extends Beverage {public Expresso() {description = "Expresso";}@Overridepublic double cost() {return 1.99; // 基礎價格1.99美元}
}
2.3 DarkRoast 咖啡
/*** 具體組件 - 深焙咖啡*/
public class DarkRoast extends Beverage {public DarkRoast() {description = "Dark Roast Coffee";}@Overridepublic double cost() {return 0.99; // 基礎價格0.99美元}
}
2.4 Decaf 咖啡
/*** 具體組件 - 低因咖啡*/
public class Decaf extends Beverage {public Decaf() {description = "Decaf Coffee";}@Overridepublic double cost() {return 1.05; // 基礎價格1.05美元}
}
3. 抽象裝飾器(CondimentDecorator)
/*** 抽象裝飾器 - 調料裝飾器基類* 繼承自Beverage,所以裝飾器可以嵌套裝飾器*/
public abstract class CondimentDecorator extends Beverage {/*** 獲取完整描述 - 抽象方法* 每個具體裝飾器需要實現如何添加自己的描述*/@Overridepublic abstract String getDescription();
}
4. 具體裝飾器(各種調料)
4.1 Milk 牛奶
/*** 具體裝飾器 - 牛奶*/
public class Milk extends CondimentDecorator {// 被裝飾的飲料Beverage beverage;public Milk(Beverage beverage) {this.beverage = beverage;}@Overridepublic String getDescription() {return beverage.getDescription() + ", Milk"; // 添加牛奶描述}@Overridepublic double cost() {return beverage.cost() + 0.10; // 增加0.10美元}
}
4.2 Mocha 摩卡
/*** 具體裝飾器 - 摩卡*/
public class Mocha extends CondimentDecorator {Beverage beverage;public Mocha(Beverage beverage) {this.beverage = beverage;}@Overridepublic String getDescription() {return beverage.getDescription() + ", Mocha"; // 添加摩卡描述}@Overridepublic double cost() {return beverage.cost() + 0.20; // 增加0.20美元}
}
4.3 Soy 豆漿
/*** 具體裝飾器 - 豆漿*/
public class Soy extends CondimentDecorator {Beverage beverage;public Soy(Beverage beverage) {this.beverage = beverage;}@Overridepublic String getDescription() {return beverage.getDescription() + ", Soy"; // 添加豆漿描述}@Overridepublic double cost() {return beverage.cost() + 0.15; // 增加0.15美元}
}
4.4 Whip 奶泡
/*** 具體裝飾器 - 奶泡*/
public class Whip extends CondimentDecorator {Beverage beverage;public Whip(Beverage beverage) {this.beverage = beverage;}@Overridepublic String getDescription() {return beverage.getDescription() + ", Whip"; // 添加奶泡描述}@Overridepublic double cost() {return beverage.cost() + 0.10; // 增加0.10美元}
}
5. 客戶端使用示例
/*** 星巴克咖啡店 - 客戶端代碼*/
public class StarbuzzCoffee {public static void main(String args[]) {// 示例1:一杯純EspressoBeverage beverage1 = new Expresso();System.out.println(beverage1.getDescription() + " $" + beverage1.cost());// 示例2:DarkRoast加雙份Mocha和WhipBeverage beverage2 = new DarkRoast();beverage2 = new Mocha(beverage2); // 第一次裝飾:加Mochabeverage2 = new Mocha(beverage2); // 第二次裝飾:再加Mochabeverage2 = new Whip(beverage2); // 第三次裝飾:加WhipSystem.out.println(beverage2.getDescription() + " $" + beverage2.cost());// 示例3:HouseBlend加Soy、Mocha和WhipBeverage beverage3 = new HouseBlend();beverage3 = new Soy(beverage3); // 第一次裝飾:加Soybeverage3 = new Mocha(beverage3); // 第二次裝飾:加Mochabeverage3 = new Whip(beverage3); // 第三次裝飾:加WhipSystem.out.println(beverage3.getDescription() + " $" + beverage3.cost());}
}
四、代碼結構說明
-
Beverage?是所有飲料的基類,定義了基本接口
-
具體咖啡類型(HouseBlend、Expresso等)繼承Beverage,實現具體價格
-
CondimentDecorator是裝飾器基類,也繼承自Beverage
-
具體調料(Milk、Mocha等)繼承CondimentDecorator,包裝一個Beverage對象
-
客戶端可以自由組合咖啡和調料,通過層層裝飾實現復雜組合
五、裝飾模式的優勢
-
靈活性:可以動態地添加或刪除功能,比繼承更靈活
-
避免類爆炸:不需要為每種組合創建子類
-
符合開閉原則:對擴展開放,對修改關閉
-
運行時添加功能:可以在運行時決定添加哪些裝飾
六、總結
? ? ? ?通過這個星巴克咖啡系統的例子,我們看到了裝飾模式在實際應用中的強大之處。它讓我們能夠輕松地組合各種咖啡和調料,而不需要創建大量的子類。這種模式特別適合那些需要動態、透明地添加對象功能的場景。