装饰器模式(Decorator) C++
装饰器模式是比较常用的一种设计模式,Python中就内置了对于装饰器的支持。
具体来说,装饰器模式是用来给对象增加某些特性或者对被装饰对象进行某些修改。
如上图所示,需要被装饰的对象在最上方,它自身可以有自己的实例,一般通过抽象类来实现(Java中也可以通过接口实现)。
右侧中间是一个装饰器类或者接口,其实内容与原对象基本一致,不过我们自定义的装饰器一般会继承这个装饰器基类。
最下层就是具体的装饰器了,可以看到,具体装饰器类中需要包含被装饰对象成员(也就是说,装饰器需要和被装饰对象有同样的子类),然后增加一些额外的操作。
下面的代码是一个买煎饼的例子,如我们生活中所见,可以选基础煎饼(鸡蛋煎饼,肉煎饼等),然后再额外加别的东西:
1 #include<iostream> 2 #include<string> 3 using namespace std; 4 5 class Pancake//基类 6 { 7 public: 8 string description = "Basic Pancake"; 9 virtual string getDescription(){ return description; } 10 virtual double cost() = 0; 11 }; 12 13 class CondimentDecorator :public Pancake//装饰器基类 14 { 15 public: 16 string getDescrition(); 17 }; 18 19 class MeatPancake :public Pancake//肉煎饼 20 { 21 public: 22 MeatPancake(){ description = "MeatPancake"; } 23 double cost(){ return 6; } 24 }; 25 class EggPancake :public Pancake//鸡蛋煎饼 26 { 27 public: 28 EggPancake(){ description = "EggPancake"; } 29 double cost(){ return 5; } 30 }; 31 32 class Egg :public CondimentDecorator//额外加鸡蛋 33 { 34 public: 35 Pancake* base; 36 string getDescription(){ return base->getDescription() + ", Egg"; } 37 Egg(Pancake* d){ base = d; } 38 double cost(){ return base->cost() + 1.5; } 39 }; 40 class Potato :public CondimentDecorator//额外加土豆 41 { 42 public: 43 Pancake* base; 44 string getDescription(){ return base->getDescription() + ", Potato"; } 45 Potato(Pancake* d){ base = d; } 46 double cost(){ return base->cost() + 1; } 47 }; 48 class Bacon :public CondimentDecorator//额外加培根 49 { 50 public: 51 Pancake* base; 52 string getDescription(){ return base->getDescription() + ", Bacon"; } 53 Bacon(Pancake* d){ base = d; } 54 double cost(){ return base->cost() + 2; } 55 }; 56 57 58 int main() 59 { 60 Pancake* pan = new EggPancake(); 61 pan = &Potato(pan); 62 pan = &Bacon(pan); 63 cout << pan->getDescription() << " $ : " << pan->cost() << endl; 64 system("pause"); 65 return 0; 66 }
可以看到,Pancake是煎饼的基类,这个基类因为定义了纯虚函数cost,所以不能被实例化。同样,装饰器基类CondimentDecorator也不能被实例化。
后面,EggPancake和MeatPancake是Pancake的派生类,是实际存在的类。
Egg、Bacon和Potato就是我们定义的装饰器对象,其中包含了Pancake的指针,可以对Pancake及其派生类进行操作。
运行代码的结果如下:
即我们选择了一个鸡蛋煎饼,然后额外加了土豆和培根,一共5+1+2=8块。
装饰器模式的优点:
1、可以轻松对已存在的对象进行修改和包装,在被装饰者的前面或者后面添加自己的行为,而无需修改原对象。
2、可以动态、不限量地进行装饰,可以更灵活地扩展功能。
相对地,装饰器模式有很明显的缺点:
1、会加入大量的小类,即使只添加一个功能,也要额外创建一个类,使得程序更复杂。
2、增加代码复杂度,使用装饰器模式不但需要实例化组件,还要把组件包装到装饰者中。