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. 避免过多的子类化以增加额外的责任。