VendingMachineDecorator

根據 Wikiepdia 定義裝飾器:

Decorator 模式可以用於靜態地(或者在某些情況下)在執行時擴充套件(裝飾)某個物件的功能,獨立於同一類的其他例項,只要在設計時完成一些基礎工作。

裝飾器動態地將附加職責附加到物件。裝飾器為子類化提供了靈活的替代擴充套件功能。

裝飾器模式包含四個元件。

StackOverflow 文件

  1. 元件介面:它定義了一個執行特定操作的介面
  2. ConcreteComponent:它實現 Component 介面中定義的操作
  3. Decorator(Abstract):它是一個抽象類,它擴充套件了元件介面。它包含元件介面。如果沒有這個類,你需要很多不同組合的 ConcreteDecorator 子類。元件的組成減少了不必要的子類。
  4. ConcreteDecorator:它包含 Abstract Decorator 的實現。

回到示例程式碼,

  1. 飲料是元件。它定義了一個抽象方法:decorateBeverage
  2. 茶葉咖啡是具體實現的飲料
  3. BeverageDecorator 是一個抽象類,其中包含 Beverage
  4. 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 文章)

  1. 介面卡為其主題提供不同的介面。代理提供相同的介面。 Decorator 提供增強的介面。

  2. 介面卡更改了物件的介面, Decorator 增強了物件的職責。

  3. CompositeDecorator 具有相似的結構圖,反映了兩者都依賴遞迴合成來組織開放數量的物件

  4. Decorator 旨在讓你在不​​進行子類化的情況下向物件新增職責。複合材料的重點不在於裝飾,而在於表現

  5. 裝飾器代理具有不同的目的但結構相似

  6. Decorator 允許你更改物件的外觀。策略可以讓你改變內心。

關鍵用例:

  1. 動態新增其他功能/職責
  2. 動態刪除功能/職責
  3. 避免過多的子類化以增加額外的責任。