场景:
购买咖啡时,可以要求加入各种调料,例如,豆浆,摩卡
豆浆,摩卡就是装饰者,咖啡是被装饰者。
不好的设计:
问题:
1、一旦出现新的调料,我们就需要加上新的方法,并改变超类中的cost方法
2、以后可能开发新的饮料,对这些饮料(冰茶),某些调料可能并不合适,但是在这个设计中,Tea子类
仍将继承那些不合法的方法,例如 奶泡。
3、万一顾客想要双倍摩卡,怎么办?
装饰者和被装饰者必须是一样的类型,也就是有共同的超类,这是相当关键的地方。
在这里,我们利用继承达到“类型匹配”,而不是利用继承获得“行为”。
当我们将装饰者与组件组合时,就是在加入新的行为,所得到的新行为,并不是继承自
超类,而是由组合对象而来。
我们可以在任何时候,实现新的装饰者增加新的行为。如果依赖继承,每当需要新行为时,
还得修改现有的代码。
类图:
//超类(抽象组件)
public abstract class Beverage{
String description = "Unknown Beverage";
public String getDescription()
{
return description;
}
public abstract double cost();
}
//抽象装饰者(调料)
public abstract class CondimentDecorator extends Beverage{
public abstract String getDescription();
}
//饮料(具体组件)
public class Espresso extends Beverage{
public Espresso ()
{
description = "Espresso";
}
public double cost()
{
return 1.99;
}
}
//调料(具体装饰者)
public class Mocha extends CondimentDecorator {
Beverage beverage;//用一个实例变量记录饮料,也就是被装饰者
public Mocha (Beverage beverage )
{
this.beverage = beverage;
}
public String getDescription()
{
return beverage.getDescription() + ", Mocha";
}
public double cost()
{
return 1.99 + beverage.cost();
}
}
摩卡(Mocha)是一个装饰者,所以让它扩展自CondimentDecorator
CondimentDecorator 扩展自Beverage
----------------------------------------------------------------------------
测试代码
public static void main(String[] args)
{
Beverage beverage = new Espresso();//一杯espresso
beverage = new Mocha(beverage); //加入调料摩卡
beverage = new Mocha(beverage); //再加入一份摩卡
//加了两份摩卡的espresso的价格
double price = beverage .cost();
}
要点:
在我们的设计中,应该允许行为可以被扩展,而无须修改现有的代码。
装饰者会导致设计中出现许多小对象,如果过度使用,会让程序变得复杂。
在选择需要被扩展的代码部分时要小心。每个地方都采用开发-关闭原则,是一种浪费,
也没必要,还会导致代码变得复杂且难以理解。