装饰者模式
意图
动态地给一个对象添加一些额外的职责。新增加功能来说,Decorator模式相比生成子类更为灵活
动机
有时我们希望给某个对象而标示整个类添加一些功能。例如,一个图形用户界面工具箱允许你对任意一个用户界面组建添加一些特征,例如边框,或者一些欣慰,例如窗口滚动。 一种较为灵活的方式是将组建潜入另一个对象中,由这个对象添加边框。我们称这个潜入的对象为装饰。这个装饰与它所装饰的组件接口一直,因此它对该组建的客户透明。
适用性
-
在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
-
处理那些可以撤销的职责。
-
当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持一每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
效果
两个优点和两个缺点:
-
比静态继承更灵活
-
避免在层次结构高层的类有太多的特征
-
Decorator与它的Component不一样 Decorator是一个透明的保包装。
-
有许多小对象
实现
注意点:
-
接口的一致性
-
省略抽象的Decorator类
-
保持Component类的简单性
-
改变对象外壳与改变对象内核
举例
购买咖啡时,可以在其中加入各种调料,例如:蒸奶(Steamed Milk),豆浆(Soy),摩卡(Mocha)或覆盖奶泡。咖啡馆会根据所加入的调料收取不同的费用。 解决方法:我们以饮料为主体,然后在运行时以调料来装饰饮料。比方说顾客想要摩卡和奶泡深焙咖啡,那么,要做的是:拿一个深焙咖啡(DarkRoast)对象,以摩卡(Mocha)对象装饰它,以奶泡对象装饰它,调用cost()方法,并依赖委托将调料的价钱加上去。
编程实现
#include <iostream> #include <string> using namespace std; class Beverage{ public: Beverage(string str = "Unknow Beverage") :description(str){} virtual string getDescription() { return description; } virtual double cost(){return 0;} private: string description; }; class CondimentDecorator:public Beverage{ public: string getDescription(){return "";} }; class Espresso:public Beverage{ public: Espresso():Beverage("Espresso"){} double cost(){ return 1.99;} }; class HouseBlend:public Beverage{ public: HouseBlend():Beverage("HouseBlend Coffee"){}; double cost(){ return 0.89;} }; class Mocha : public CondimentDecora{ public: Mocha(Beverage* beve){ beverage = beve; } string getDescription(){ return beverage->getDescription + ", Mocha"; } double cost(){ return 0.20 + beverage->cost(); } private: Beverage* beverage; }; class Whip : public CondimentDecorator { public: Whip(Beverage* beve) { beverage = beve; } string getDescription() { return beverage->getDescription()+", Whip"; } double cost() { return 0.15 + beverage->cost(); } private: Beverage* beverage; }; int main() { Beverage* pBeverage = new Espresso(); cout << pBeverage->getDescription() << " $" << pBeverage->cost() <<endl; Beverage* pBeverage2 = new Espresso(); pBeverage2 = new Mocha(pBeverage2); pBeverage2 = new Mocha(pBeverage2); cout << pBeverage2->getDescription() << " $" << pBeverage2->cost() <<endl; pBeverage2 = new Whip(pBeverage2); cout << pBeverage2->getDescription() << " $" << pBeverage2->cost() <<endl; return 0; }
设计原则的应用
** 设计原则5:类应该对外扩展,对修改关闭。**如装饰者模式中,我们的目标是允许类容易扩展,在不修改现有代码的情况下,就可搭配新的行为。