本文共 4891 字,大约阅读时间需要 16 分钟。
前言
在实际开发时,你有没有碰到过这种问题;开发一个类,封装了一个对象的核心操作,而这些操作就是客户使用该类时都会去调用的操作;而有一些非核心的操作,可能会使用,也可能不会使用;现在该怎么办呢?
什么是装饰模式?
在GOF的《设计模式:可复用面向对象软件的基础》一书中对装饰模式是这样说的:动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。
装饰模式能够实现动态的为对象添加功能,是从一个对象外部来给对象添加功能。通常给对象添加功能,要么直接修改对象添加相应的功能,要么派生对应的子类来扩展,抑或是使用对象组合的方式。显然,直接修改对应的类这种方式并不可取。在面向对象的设计中,而我们也应该尽量使用对象组合,而不是对象继承来扩展和复用功能。装饰器模式就是基于对象组合的方式,可以很灵活的给对象添加所需要的功能。装饰器模式的本质就是动态组合。动态是手段,组合才是目的。总之,装饰模式是通过把复杂的功能简单化,分散化,然后再运行期间,根据需要来动态组合的这样一个模式。它使得我们可以给某个对象而不是整个类添加一些功能。
UML类图
Component:定义一个对象接口,可以给这些对象动态地添加职责;
ConcreteComponent:定义一个具体的Component,继承自Component,重写了Component类的虚函数;
Decorator:维持一个指向Component对象的指针,该指针指向需要被装饰的对象;并定义一个与Component接口一致的接口;
ConcreteDecorator:向组件添加职责。
代码实现:
#includeusing namespace std;//装饰器模式class Component{public: virtual void Operation() = 0;};//没有装饰器的组件,这个可以理解为核心功能class ConcreteComponent :public Component{public: void Operation() { cout << "没有装饰器的组件" << endl; }};//装饰器class Decorator :public Component{public: Decorator(Component* pComponent) { m_pComponentObj = pComponent; } void Operation() { if (m_pComponentObj!=NULL) { m_pComponentObj->Operation(); } }protected: Component* m_pComponentObj;};//用装饰器修饰的组件Aclass ConcreteComponentA :public Decorator{public: ConcreteComponentA(Component* pComponent):Decorator(pComponent){} void Operation() { addBehavior(); //在核心功能的基础上新增加的装饰器A Decorator::Operation(); } void addBehavior() { cout << "装饰器A" << endl; }};//装饰器修饰的组件Bclass ConcreteComponentB :public Decorator{public: ConcreteComponentB(Component* pComponent) :Decorator(pComponent) {} void Operation() { addBehavior(); Decorator::Operation(); } void addBehavior() { cout << "装饰器B" << endl; }};int main(int argc, char* argv[]){ Component* component = new ConcreteComponent(); Component* componentA = new ConcreteComponentA(component); componentA->Operation(); cout << "------------------------" << endl; Component* componentB = new ConcreteComponentB(component); componentB->Operation(); cout << "-------------------------" << endl; Component* componentC = new ConcreteComponentB(componentA); componentC->Operation(); if (component != NULL) { delete component; component = NULL; } if (componentA != NULL) { delete componentA; componentA = NULL; } if (componentB != NULL) { delete componentB; componentB = NULL; } if (componentC != NULL) { delete componentC; componentC = NULL; } return 0;}
使用场合
注意事项
实现要点
与桥接模式的区别
之前总结了;你会发现,二者都是为了防止过度的继承,从而造成子类泛滥的情况。那么二者之间的主要区别是什么呢?桥接模式的定义是将抽象化与实现化分离(用组合的方式而不是继承的方式),使得两者可以独立变化。可以减少派生类的增长。如果光从这一点来看的话,和装饰者差不多,但两者还是有一些比较重要的区别:
总结
装饰模式重点在装饰,对核心功能的装饰作用;将继承中对子类的扩展转化为功能类的组合,从而将需要对子类的扩展转嫁给用户去进行调用组合,用户如何组合由用户去决定。我在学习装饰模式时,就是重点分析了“装饰”这个词,我们都知道,装饰是在一个核心功能上添加一些附属功能,从而让核心功能发挥更大的作用,但是最终它的核心功能是不能丢失的。这就好比我们进行windows shell开发时,我们是对windows的这层壳进行了功能的装饰,从而实现了我们需要的一些装饰功能,但是最终的功能还是由windows shell去完成。这就好比,我们的装饰就是给核心功能添加了一层外衣,让它看起来更漂亮和完美。