装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
装饰者模式的整体思路比较简单,就是在类的实例中包含一个同类型的成员变量,然后用实例来装饰该成员变量。这样就就可以实现嵌套装饰。
书中该部分的例子是咖啡。
Coffee.h
class Beverage { public: virtual std::string getDescription(); virtual double cost() = 0; protected: std::string description = ""; }; class Espresso: public Beverage { public: Espresso(); double cost(); }; class Mocha: public Beverage { public: Mocha(Beverage* b); ~Mocha(); std::string getDescription(); double cost(); private: Beverage* beverage; };
Coffee.cpp
#include <iostream> #include "Coffee.h" std::string Beverage::getDescription() { return description; } Espresso::Espresso() { description = "Espresso"; } double Espresso::cost() { return 1.99; } Mocha::Mocha(Beverage* b) { beverage = b; } Mocha::~Mocha() { delete beverage; } std::string Mocha::getDescription() { return beverage->getDescription()+" Mocha"; } double Mocha::cost() { return beverage->cost()+0.2; }
需要注意的问题:
1. 构造函数中的参数要传指针。或者这么说,我现在认为这种继承关系,用父类作为参数类型的时候,都应该传指针,这样不容易导致问题。(我的理解是,如果是用引用进行传递,其传入的数据的类型就是父类的类型,这会导致在调用成员函数的时候出现问题)
2. 忘记用列表初始化了(捂脸)。
blog中装饰模式的例子是装饰手机,基本上与书中咖啡的例子相同。见:https://blog.csdn.net/wuzhekai1985/article/details/6672614
两者相比:
1. 根据blog的代码,基本上证明了我自己实现中的猜想(1)。
2. 根据测试代码,继承的类型,在新建实例的时候,也是以指针的形式来完成的。比如
Phone *iphone = new NokiaPhone("6300"); Phone *dpa = new DecoratorPhoneA(iphone); //装饰,增加挂件 、
Phone *dpb = new DecoratorPhoneB(dpa); //装饰,屏幕贴膜