意图/目的/定义(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';
}
@override
double cost() {
return 1.99;
}
}
/// 综合咖啡,继承自Beverage类
class HouseBlend extends Beverage {
HouseBlend() {
description = 'House Blend Coffee';
}
@override
double cost() {
return 0.89;
}
}
// 深培咖啡
class DarkRoast extends Beverage {
DarkRoast() {
description = 'Dark Roast Coffee';
}
@override
double cost() {
return 0.99;
}
}
/// ------------------ 调料代码
// 摩卡是一个装饰者调料,所以它扩展自CondimentDecorator。
class Mocha extends CondimentDecorator {
// 用一个实例变量记录饮料,也就是被装饰者。
// 想办法让被装饰着被记录到实例变量中。
// 这里的做法是:把饮料当做构造器函数的参数,有构造函数将饮料记录在实例变量中。
Beverage _beverage;
Mocha(Beverage beverage) {
this._beverage = beverage;
}
// 我们希望叙述不只是描述饮料,而是完整的连调料都描述出来。
// 首先利用委托的做法,得到一个叙述,然后在其后加上附加的叙述。
@override
String getDescription() {
return '${_beverage.getDescription()}, Mocha';
}
@override
double cost() {
// 要计算mocha饮料的价钱。
// 首先把调用委托给被装饰者对象,以计算价钱,然后再加上mocha的价钱,得到最后结果
return 0.20 + _beverage.cost();
}
}
// 豆浆
class Soy extends CondimentDecorator {
Beverage _beverage;
Soy(Beverage beverage) {
_beverage = beverage;
}
@override
String getDescription() {
return '${_beverage.getDescription()}, Soy';
}
@override
double cost() {
return 0.15 + _beverage.cost();
}
}
// 奶泡
class Whip extends CondimentDecorator {
Beverage _beverage;
Whip(Beverage beverage) {
_beverage = beverage;
}
@override
String getDescription() {
return '${_beverage.getDescription()}, Whip';
}
@override
double cost() {
return 0.10 + _beverage.cost();
}
}
// 牛奶
class Milk extends CondimentDecorator {
Beverage _beverage;
Milk(Beverage beverage) {
_beverage = beverage;
}
@override
String getDescription() {
return '${_beverage.getDescription()}, Milk';
}
@override
double 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原则
- 封装变化
- 多用组合少用继承
- 针对接口编程,不针对实现编程
- 为交互对象之间的松耦合设计而努力
-
要点
继承属于扩展形式之一,但不见得是达到弹性设计的最佳方案。
- 在我们的设计中,应该允许行为可以被扩展,而无需修改现有的代码。
- 组合和委托可用于在运行时动态的加上新的行为。
- 除了继承,装饰者模式也可以让我们扩展行为。
- 装饰者模式意味着一群装饰者类,这些类用来包装具体组件。
- 装饰者类反映出被装饰的组件类型(事实上,他们具有相同的类型,都经过接口或继承实现)。
- 装饰者可以在被装饰者的行为前面与/或后面加上自己的行为,甚至将被装饰者的行为整个取代掉,而达到特定的目的。
- 你可以用无数个装饰者包装一个组件。
- 装饰者一般对组件的客户是透明的,除非客户程序依赖于组件的具体类型。
- 装饰者会导致设计中出现许多小对象,如果过度使用,会让程序变得很复杂。