定义:动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案。(一层套一层)
下边是Head First 书上的例子:
星巴兹咖啡准备更新订单系统,以合乎他们的饮料供应需求。
他们原先的类设计为:
这样的订单系统没有办法考虑到咖啡调料的部分,把加入不同调料的咖啡看做不同的类会导致类爆炸(每个类的cost方法计算出咖啡加调料的价钱):
很明显,这样的系统难以维护,一旦牛奶的价钱上扬或新增一种焦糖调料,系统将难以改变。
采用实例变量和继承的设计也许能解决一些问题:
Beverage作为一个饮料类,加上实例变量代表是否加入了饮料。
然而当用户想要双倍摩卡咖啡时,这样的系统就显得有些无所适从。
对于冰茶,饮料基类里的有些调料根本不适用,但是也一起继承了过来!
到目前为止,使用继承会造成的问题有:类爆炸,设计死板,以及基类加入的新功能并不适用于所有的子类。
所以继承并不是解决问题的方法,应当使用组合来使系统更有弹性且易于维护。
开放-关闭原则:
设计原则:
类应该对扩展开放,对修改关闭。
我们的目标是允许类容易扩展,在不修改现有代码的情况下,就可搭配新的行为。
这个目标需要使用装饰着模式实现:以饮料为主体,然后运行调料来“装饰”饮料。
如图为一个摩卡和奶泡DarkRoast咖啡的设计图:
装饰者模式类图:
现在让星巴兹咖啡系统也符合装饰者类图:
c++代码如下:
#include <iostream> using namespace std; class Beverage{ private: string description; public: //Beverage(){} Beverage():description("Unknown Beverage"){} Beverage(string i):description(i){} virtual string getDescription(){ return description; } virtual double cost()=0; }; class Espresso:public Beverage{ public: Espresso():Beverage("Espresso"){} double cost(){ return 1.99; } }; class HouseBlend:public Beverage{ public: HouseBlend():Beverage("House Blend Coffee"){} double cost(){ return 0.89; } }; class DarkRoast:public Beverage{ public: DarkRoast():Beverage("Dark Roast Coffee"){} double cost(){ return 0.99; } }; class CondimentDecorator:public Beverage{ public: virtual string getDescription()=0; }; class Mocha:public CondimentDecorator{ Beverage *beverage; public: Mocha(Beverage *beverage){ this->beverage = beverage; } string getDescription(){ return beverage->getDescription()+", Mocha"; } double cost(){ return 0.20 + beverage->cost(); } }; class Whip:public CondimentDecorator{ Beverage *beverage; public: Whip(Beverage *beverage){ this->beverage = beverage; } string getDescription(){ return beverage->getDescription()+", Whip"; } double cost(){ return 0.19 + beverage->cost(); } } ; class Soy:public CondimentDecorator{ Beverage *beverage; public: Soy (Beverage* beverage){ this->beverage = beverage; } string getDescription(){ return beverage->getDescription()+", Soy"; } double cost(){ return 0.10 + beverage->cost(); } }; int main(int argc, const char * argv[]) { // insert code here... //std::cout << "Hello, World!\n"; Beverage *beverage = new Espresso(); cout<<beverage->getDescription()<<"