装饰者模式 (Decorator Pattern) 非常有趣,如果不是看过设计模式,看到这个模式的代码时一定大吃一惊:“这是什么东西?怎么这么多类!”
是的,这就是这个模式的特别之处了,无数类摆在你面前,你无所适从。但这个模式是用来干什么的呢?用来管理大量同样类型但有细小属性差别的事物(我自己想的定义)。这也就注定了这个模式中,类的多样性。
为什么会出现这么个模式?
如果是我自己编程,我第一个想到的,肯定是继承。一个抽象类,其他各种功能的子类。
这样设计是多么丑陋你应该一眼就看出来了,因为只要一个小小的改变,你就需要重新复制出一份新类的代码。
诶,等等,我前面不是写过一篇文章关于策略模式的嘛?难道不能用这样的方法来扩展它们的属性嘛?说实话,按我的想法,这也是可行的。但这个问题还是等我们了解了装饰者以后再说吧。
装饰者模式:动态的将责任附加到对象上。若要扩展功能,装饰者提供比继承更具弹性的替代方案。
看到这个说明,似乎装饰者只能通过增加的方式赋予原始对象以新的职责。如果你认为覆盖一个空的方法也是增加的话,那确实是这样的。装饰者模式通过不断的包装原有对象,使其属性改变。
下面我们来看一看如何实现:
此图为Head First上的截图。很清晰的说明了装饰者实现的方式,继承自同一基类,包含两类——对象和装饰者。
如何包装呢?
看一个实例——咖啡店的咖啡:
咖啡有很多种,而每一种又可以配多种调料,那么我们可以构建出多个咖啡对象和调料装饰者,然后以咖啡为基底,包装上各种调料,类图如下:
咖啡的cost函数直接返回其价格,调料的cost价格则为本身的价格加上beverage的价格。这样,在一层层的封装下,价格也随之累计。
getDescription函数类似,可以得到包装的清单。
在这样的装饰者模式包装之下,裸露的咖啡可以被一层层的包装上各种调料,另一方面,调料为咖啡动态的附加了计算调料价格和描述的职责。
回到我之前留下的疑问。策略模式能否实现这样的需求?
我想,如果只是添加属性,增加单一的职责,对策略模式进行扩展以后是可行的,只需将策略模式中对象的行为属性改为行为列表属性即可动态的添加不同的行为。
对于上文提到的咖啡店情景,我们可以这样编程:
/* * 调料类 */ class Condiment { private: string description; float cost; public: float getCost() { return cost; } string getDescription() { return description; } }; /* * 咖啡类 */ class Coffee { private: string description; float cost; list<Condiment *> condiments; public: // 循环获取各种调料的价格并累加。 float getCost() { float totalCost = cost; foreach (Condiment cond, condiments) totalCost += cond.getCost(); return totalCost; } // 循环获取各种调料的描述并累加。 string getDescription() { string totalDescription = string("Made by: ") + description; foreach (Condiment cond, condiments) totalDescription += string(", ") + cond.getDescription(); return totalDescription; } /////////////////////////////////////////////////////// // 下面是重点,添加调料 void addCondiment(Condiment * cond) { condiments.push_back(cond); } };
只写出两个基类。我不知道这样扩展以后还能不能算是策略模式。另外,对于上述咖啡问题,似乎我的方法也能奏效,并且同样能动态添加(甚至很容易实现动态删除!)属性。
当然,有一种情形是策略模式办不到的。那就是如第一副类图中的ConcreteDecoratorA,它有一个newBehavior,可以添加新的职能,而策略模式不修改代码是行不通的。
从这个对比我们也可以看出他们俩的本质:
策略模式注重算法的独立(cost和description的获取);
装饰者模式注重职能的增加。
不知这样的理解是否正确,求鉴定。。
OK,七七八八写了一大堆,就这么多了。