意图/目的/定义(intent)
(简短的描述该模式的作用。)
装饰者模式动态的将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
动机(motivation)
(动机给出来问题以及如何解决这个问题的具体场景。)
星巴兹咖啡的订单实现。
适用性(applicability)
结构(structure)
参与者(participants)
(参与者描述在此设计中所涉及到的类和对象在模式中的责任和角色。)
协作(collaborations)
实现/范例代码(implementation/sample code)
(实现提供了你在实现该模式时需要使用的技巧,以及你应该小心面对的问题。)
(范例代码提供代码的片段,可能对你的实现有多帮助。)
/// 饮料抽象类abstract class Beverage {String description = "Unknown Beverage";String getDescription() {return description;}double cost();}/// 调料抽象类,继承饮料类abstract class CondimentDecorator extends Beverage {// 调料类装饰者重新实现getDescription()方法String getDescription();}/// --------------- 饮料代码// 浓缩咖啡是一种饮料,继承Beverage类class Espresso extends Beverage {Espresso() {description = 'Espresso';}@overridedouble cost() {return 1.99;}}/// 综合咖啡,继承自Beverage类class HouseBlend extends Beverage {HouseBlend() {description = 'House Blend Coffee';}@overridedouble cost() {return 0.89;}}// 深培咖啡class DarkRoast extends Beverage {DarkRoast() {description = 'Dark Roast Coffee';}@overridedouble cost() {return 0.99;}}/// ------------------ 调料代码// 摩卡是一个装饰者调料,所以它扩展自CondimentDecorator。class Mocha extends CondimentDecorator {// 用一个实例变量记录饮料,也就是被装饰者。// 想办法让被装饰着被记录到实例变量中。// 这里的做法是:把饮料当做构造器函数的参数,有构造函数将饮料记录在实例变量中。Beverage _beverage;Mocha(Beverage beverage) {this._beverage = beverage;}// 我们希望叙述不只是描述饮料,而是完整的连调料都描述出来。// 首先利用委托的做法,得到一个叙述,然后在其后加上附加的叙述。@overrideString getDescription() {return '${_beverage.getDescription()}, Mocha';}@overridedouble cost() {// 要计算mocha饮料的价钱。// 首先把调用委托给被装饰者对象,以计算价钱,然后再加上mocha的价钱,得到最后结果return 0.20 + _beverage.cost();}}// 豆浆class Soy extends CondimentDecorator {Beverage _beverage;Soy(Beverage beverage) {_beverage = beverage;}@overrideString getDescription() {return '${_beverage.getDescription()}, Soy';}@overridedouble cost() {return 0.15 + _beverage.cost();}}// 奶泡class Whip extends CondimentDecorator {Beverage _beverage;Whip(Beverage beverage) {_beverage = beverage;}@overrideString getDescription() {return '${_beverage.getDescription()}, Whip';}@overridedouble cost() {return 0.10 + _beverage.cost();}}// 牛奶class Milk extends CondimentDecorator {Beverage _beverage;Milk(Beverage beverage) {_beverage = beverage;}@overrideString getDescription() {return '${_beverage.getDescription()}, Milk';}@overridedouble cost() {return 0.10 + _beverage.cost();}}/// 测试函数main(List<String> args) {Beverage beverage = new Espresso();print('${beverage.getDescription()} \$ ${beverage.cost()}');Beverage beverage2 = new DarkRoast();beverage2 = new Mocha(beverage2);beverage2 = new Milk(beverage2);beverage2 = new Whip(beverage2);print('${beverage2.getDescription()} \$ ${beverage2.cost()}');Beverage beverage3 = new HouseBlend();beverage3 = new Mocha(beverage3);beverage3 = new Mocha(beverage3);beverage3 = new Soy(beverage3);print('${beverage3.getDescription()} \$ ${beverage3.cost()}');}
已知应用(known uses)
相关模式(related patterns)
OO知识
OO基础
- 抽象
- 封装
- 多态
- 继承
OO原则
- 封装变化
- 多用组合少用继承
- 针对接口编程,不针对实现编程
- 为交互对象之间的松耦合设计而努力
-
要点
继承属于扩展形式之一,但不见得是达到弹性设计的最佳方案。
- 在我们的设计中,应该允许行为可以被扩展,而无需修改现有的代码。
- 组合和委托可用于在运行时动态的加上新的行为。
- 除了继承,装饰者模式也可以让我们扩展行为。
- 装饰者模式意味着一群装饰者类,这些类用来包装具体组件。
- 装饰者类反映出被装饰的组件类型(事实上,他们具有相同的类型,都经过接口或继承实现)。
- 装饰者可以在被装饰者的行为前面与/或后面加上自己的行为,甚至将被装饰者的行为整个取代掉,而达到特定的目的。
- 你可以用无数个装饰者包装一个组件。
- 装饰者一般对组件的客户是透明的,除非客户程序依赖于组件的具体类型。
- 装饰者会导致设计中出现许多小对象,如果过度使用,会让程序变得很复杂。
