装饰者模式
运行时扩展,远比编译时继承威力大。
熟悉了装饰的技巧,能够在不改变任何底层代码的情况下,给你的对象赋予新的职责。
星巴兹咖啡
星巴兹starbuzz以扩张速度快闻名,准备更新订单系统,以适应他们的饮料供应要求。
原先类的设计:
现在想购买咖啡时,可以要求在其中加入各种调料,如蒸奶(Steamed Milk)、豆浆(soy)、摩卡(mocha,也就是巧克力风味)或覆盖奶泡,根据加入的调料收取不同费用,订单系统需要考虑这些调料部分。
这样子类通过覆盖cost()扩展超类的功能,计算指定的饮料类型加入调料的价格
其实还是有潜在的问题:
- 调料价格改变会使我们更改现有代码
- 一旦出现新的调料,需要加入新的方法,并改变超类的cost()方法
- 以后可能开发新的饮料,如冰茶,某些调料并不合适,如奶泡whip,但子类仍然要继承
- 万一顾客想要双倍摩卡咖啡,怎么办
开放关闭原则
设计原则:类应该对扩展开放,对修改关闭
目标是允许类容易扩展,在不修改现有代码的情况下,就可搭配新的行为。如能实现这样的目标,会具有弹性可以应对改变,可以接受新的功能应对改变的需求。
对扩展开放,对修改关闭,如何兼顾
乍听很矛盾,越难修改的食物,就越难扩展。
但有些聪明的OO技巧,如之前的观察者模式,通过加入新的观察者,可在任何时候扩展主题subject,而且不需要向主题中加入代码。
如何将某件东西设计为可以扩展,又禁止修改
使用装饰者模式就是很好的例子
如何让设计的每个部分都遵循开放-关闭原则
通常办不到也没必要。遵循开放-关闭原则,通常会引入新的抽象层次,增加代码的复杂度,需要将注意力集中在设计中最有可能改变的地方,然后应用开放-关闭原则。
如何知道哪些地方的改变最重要
涉及到经验和对工作领域的了解程度。
认识装饰者模式
利用继承无法完全解决问题,在星巴兹遇到的问题有:类数量爆炸、设计死板,以及基类加入的新功能并不适用于所有子类。
需要采取不一样的做法:以饮料为主体,然后在运行时以调料来装饰(decorate)饮料。如,如果顾客想要摩卡和奶泡深焙咖啡,要做的是:
- 拿一个DarkRoast对象
- 以摩卡Mocha对象装饰它
- 以奶泡whip对象装饰它
- 调用cost()方法,并依赖委托delegate将调料的价格加上去
如何装饰一个对象,而委托又要如何与此搭配使用呢?把装饰者对象看做“包装者”
以装饰者构造饮料订单
未完待续
TODO