星巴兹是以扩张速度最快而闻名的咖啡连锁店。因为扩张速度过快,他们准备更新订单系统,以合乎他们的饮料供应要求。他们原先类设计是这样的。。
购买咖啡时,要求在其中加入各种调料,例如:蒸奶(steamed milk),豆浆(Soy)、摩卡(Mocha)或者其他。所以它们的订单系统必须考虑到调料部分。
他们尝试一次使用继承解决,如下图:
很明显如果每家一种调料都生成一个新类来继承父类Beverage,将会产生“类爆炸”,维护起来十分困难,如果调料价格上涨,新增调料,都会十分难以管理。
那么再尝试另外一种设计。
在父类Beverage中加上成员变量牛奶(milk)、豆浆(soy)、摩卡(mocha)、奶泡(whip.....)
这样的设计看起立已经比先前好多了。但是因为子类是直接继承父类的通用共享的成员变量和方法。所以扩展性,和代码会存在冗余。
例如:(1)增加新的饮料,比如茶,某些调料可能不适合,但在这个设计方式中,Tea子类仍将继承那些不合适的方法,例如hasWhip()(加奶泡)
(2)调料的价钱改变需要改变现有代码
(3)顾客想要双倍摩卡咖啡
认识装饰这模式
现在我们知道继承很好的解决我们的问题,上面设计中我们遇到了:类数量爆炸、设计死板、以及基类加入的功能并不适合所有的子类。
所以现在我们采用装饰者模式:我们以饮料为主体,然后运行时以调料来装饰饮料,比方说顾客想要摩卡和奶泡深焙咖啡,要做的是:
- 拿一个深焙咖啡(DarkRoast)对象
- 以摩卡(Mocha)对象装饰它
- 以奶泡(Whip)对象修饰它
- 调用cost()方法,并依赖委托(delegate)将调料的将钱加上去
以装饰者构造饮料订单
(1)以DarkRoast对象开始
(2)顾客想要摩卡(Mocha),所以建立一个摩卡(Mocha)对象,并用它将DarkRoast对象包装起来。
(3)顾客也想要奶泡(Whip),所以要建立一个Whip装饰者,并用它将Mocha对象包起来。
(4)现在,是为顾客算钱的时候了。通过调用最外圈装饰者(Whip)的cost()就可以办到。Whip的cost()会委托它的装饰的对象计算出价钱,然后再加上奶泡的价钱。
目前通过上面的信息我们可以知道
- 装饰者和被装饰者有相同的超类型。
- 你可以用一个或者多个装饰者包装一个对象
- 既然装饰者和被装饰对象有相同的类型,所以在任何需要原始对象(被包装的)场合,可以用装饰过的对象代替。
- 装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的。
- 对象可以在任何时候被装饰,所以可以在运行时动态装饰想要装饰的对象。
定义装饰者模式
装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的方案。
装饰饮料
写饮料的具体代码
Beverage相当于Component类
public abstract class Beverage {
String description = "Unknow Beverage";
public String getDescription() {
return description;
}
public abstract double cost();
}
DarkRost相当于具体组件
public class DarkRost extends Beverage {
public DarkRost() {
description = "DarkRost";
}
@Override
public double cost() {
return 100;
}
}
CondimentDecorator抽象装饰者
public abstract class CondimentDecorator extends Beverage{
public abstract String getDescription();
}
具体装饰者Mocha
public class Mocha extends CondimentDecorator {
Beverage beverage;
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
@Override
public String getDescription() {
return beverage.getDescription()+",Mocha";
}
@Override
public double cost() {
return 20+ beverage.cost();
}
}
具体装饰者Whip
public class Whip extends CondimentDecorator {
Beverage beverage;
public Whip(Beverage beverage) {
this.beverage = beverage;
}
@Override
public String getDescription() {
return beverage.getDescription()+",whip";
}
@Override
public double cost() {
return 30+beverage.cost();
}
}
测试
public class Test {
public static void main(String[] args) {
Beverage beverage = new DarkRost();
System.out.println(beverage.description+" ,cost:"+beverage.cost());
beverage = new Mocha(beverage);
System.out.println(beverage.getDescription()+" ,cost:"+beverage.cost());
beverage = new Whip(beverage);
System.out.println(beverage.getDescription()+" ,cost:"+beverage.cost());
}
}
输出结果:DarkRost ,cost:100.0
DarkRost,Mocha ,cost:120.0
DarkRost,Mocha,whip ,cost:150.0