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 允许你更改对象的外观。策略可以让你改变内心。
关键用例:
- 动态添加其他功能/职责
- 动态删除功能/职责
- 避免过多的子类化以增加额外的责任。