VendingMachineDecorator
根據 Wikiepdia 定義裝飾器:
Decorator 模式可以用於靜態地(或者在某些情況下)在執行時擴充套件(裝飾)某個物件的功能,獨立於同一類的其他例項,只要在設計時完成一些基礎工作。
裝飾器動態地將附加職責附加到物件。裝飾器為子類化提供了靈活的替代擴充套件功能。
裝飾器模式包含四個元件。
- 元件介面:它定義了一個執行特定操作的介面
- ConcreteComponent:它實現 Component 介面中定義的操作
Decorator(Abstract)
:它是一個抽象類,它擴充套件了元件介面。它包含元件介面。如果沒有這個類,你需要很多不同組合的 ConcreteDecorator 子類。元件的組成減少了不必要的子類。- ConcreteDecorator:它包含 Abstract Decorator 的實現。
回到示例程式碼,
- 飲料是元件。它定義了一個抽象方法:decorateBeverage
- 茶葉和咖啡是具體實現的飲料。
- BeverageDecorator 是一個抽象類,其中包含 Beverage
- SugarDecorator 和 LemonDecorator 是 BeverageDecorator 的具體裝飾器。
編輯: 更改了示例以反映通過新增一種或多種口味(如糖,檸檬等)來計算飲料價格的真實場景(口味是裝飾器)
abstract class Beverage {
protected String name;
protected int price;
public Beverage(){
}
public Beverage(String name){
this.name = name;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
protected void setPrice(int price){
this.price = price;
}
protected int getPrice(){
return price;
}
protected abstract void decorateBeverage();
}
class Tea extends Beverage{
public Tea(String name){
super(name);
setPrice(10);
}
public void decorateBeverage(){
System.out.println("Cost of:"+ name +":"+ price);
// You can add some more functionality
}
}
class Coffee extends Beverage{
public Coffee(String name){
super(name);
setPrice(15);
}
public void decorateBeverage(){
System.out.println("Cost of:"+ name +":"+ price);
// You can add some more functionality
}
}
abstract class BeverageDecorator extends Beverage {
protected Beverage beverage;
public BeverageDecorator(Beverage beverage){
this.beverage = beverage;
setName(beverage.getName()+"+"+getDecoratedName());
setPrice(beverage.getPrice()+getIncrementPrice());
}
public void decorateBeverage(){
beverage.decorateBeverage();
System.out.println("Cost of:"+getName()+":"+getPrice());
}
public abstract int getIncrementPrice();
public abstract String getDecoratedName();
}
class SugarDecorator extends BeverageDecorator{
public SugarDecorator(Beverage beverage){
super(beverage);
}
public void decorateBeverage(){
super.decorateBeverage();
decorateSugar();
}
public void decorateSugar(){
System.out.println("Added Sugar to:"+beverage.getName());
}
public int getIncrementPrice(){
return 5;
}
public String getDecoratedName(){
return "Sugar";
}
}
class LemonDecorator extends BeverageDecorator{
public LemonDecorator(Beverage beverage){
super(beverage);
}
public void decorateBeverage(){
super.decorateBeverage();
decorateLemon();
}
public void decorateLemon(){
System.out.println("Added Lemon to:"+beverage.getName());
}
public int getIncrementPrice(){
return 3;
}
public String getDecoratedName(){
return "Lemon";
}
}
public class VendingMachineDecorator {
public static void main(String args[]){
Beverage beverage = new SugarDecorator(new LemonDecorator(new Tea("Assam Tea")));
beverage.decorateBeverage();
beverage = new SugarDecorator(new LemonDecorator(new Coffee("Cappuccino")));
beverage.decorateBeverage();
}
}
輸出:
Cost of:Assam Tea:10
Cost of:Assam Tea+Lemon:13
Added Lemon to:Assam Tea
Cost of:Assam Tea+Lemon+Sugar:18
Added Sugar to:Assam Tea+Lemon
Cost of:Cappuccino:15
Cost of:Cappuccino+Lemon:18
Added Lemon to:Cappuccino
Cost of:Cappuccino+Lemon+Sugar:23
Added Sugar to:Cappuccino+Lemon
該實施例在向飲料中新增許多香料後計算自動售貨機中的飲料成本。
在上面的例子中:
茶的成本= 10,檸檬= 3,糖= 5.如果你製作糖+檸檬+茶,它的成本是 18。
咖啡的成本= 15,檸檬= 3,糖= 5.如果你製作糖+檸檬+咖啡,它的成本是 23
通過對兩種飲料(茶和咖啡)使用相同的裝飾器,子類的數量已經減少。如果沒有 Decorator 模式,你應該為不同的組合使用不同的子類。
組合將是這樣的:
SugarLemonTea
SugarTea
LemonTea
SugarLemonCapaccuino
SugarCapaccuino
LemonCapaccuino
等等
通過對兩種飲料使用相同的 Decorator
,子類的數量已經減少。這可能是由於這種模式中使用的 composition
而不是 inheritance
概念。
與其他設計模式的比較(來自 sourcemaking 文章)
-
介面卡為其主題提供不同的介面。代理提供相同的介面。 Decorator 提供增強的介面。
-
介面卡更改了物件的介面, Decorator 增強了物件的職責。
-
Composite 和 Decorator 具有相似的結構圖,反映了兩者都依賴遞迴合成來組織開放數量的物件
-
Decorator 旨在讓你在不進行子類化的情況下向物件新增職責。複合材料的重點不在於裝飾,而在於表現
-
裝飾器和代理具有不同的目的但結構相似
-
Decorator 允許你更改物件的外觀。策略可以讓你改變內心。
關鍵用例:
- 動態新增其他功能/職責
- 動態刪除功能/職責
- 避免過多的子類化以增加額外的責任。