0 引言
0.1 目的
本文档给出设计模式之——Decorator模式的简化诠释,并给出其C++实现。
0.2 说明
Project |
Design Pattern Explanation(By K_Eckel) |
Authorization |
Free Distributed but Ownership Reserved |
Date |
|
Test Bed |
MS Visual C++ 6.0 |
0.3 参考
在本文档的写作中,参考了以下的资源,在此列出表示感谢:
u 书籍
[GoF 2000]:GoF,Design Patterns-Elements of Reusable Object-Oriented Software
Addison-Wesley 2000/9.
[Martine 2003]:Robert C.Martine, Agile Software Development Principles, Patterns, and Practices, Pearson Education, 2003.
0.4 联系作者
Author |
K_Eckel |
State |
Candidate for Master’s Degree School of |
E_mail |
2 Decorator模式
2.1 问题
在OO设计和开发过程,可能会经常遇到以下的情况:我们需要为一个已经定义好的类添加新的职责(操作),通常的情况我们会给定义一个新类继承自定义好的类,这样会带来一个问题(将在本模式的讨论中给出)。通过继承的方式解决这样的情况还带来了系统的复杂性,因为继承的深度会变得很深。
而Decorator提供了一种给类增加职责的方法,不是通过继承实现的,而是通过组合。有关这些内容在讨论中进一步阐述。
2.2 模式选择
Decorator模式典型的结构图为:
图2-1:Decorator Pattern结构图
在结构图中,ConcreteComponent和Decorator需要有同样的接口,因此ConcreteComponent和Decorator有着一个共同的父类。这里有人会问,让Decorator直接维护一个指向ConcreteComponent引用(指针)不就可以达到同样的效果,答案是肯定并且是否定的。肯定的是你可以通过这种方式实现,否定的是你不要用这种方式实现,因为通过这种方式你就只能为这个特定的ConcreteComponent提供修饰操作了,当有了一个新的ConcreteComponent你又要去新建一个Decorator来实现。但是通过结构图中的ConcreteComponent和Decorator有一个公共基类,就可以利用OO中多态的思想来实现只要是Component型别的对象都可以提供修饰操作的类,这种情况下你就算新建了100个Component型别的类ConcreteComponent,也都可以由Decorator一个类搞定。这也正是Decorator模式的关键和威力所在了。
当然如果你只用给Component型别类添加一种修饰,则Decorator这个基类就不是很必要了。
2.3 实现
2.3.1 完整代码示例(code)
Decorator模式的实现起来并不是特别困难,这里为了方便初学者的学习和参考,将给出完整的实现代码(所有代码采用C++实现,并在VC 6.0下测试运行)。
代码片断1:Decorator.h #ifndef _DECORATOR_H_ class Component virtual void Operation(); protected: private: }; class ConcreteComponent:public Component ~ConcreteComponent(); void Operation(); protected: private: }; class Decorator:public Component virtual ~Decorator(); void Operation(); protected: private: class ConcreteDecorator:public Decorator ~ConcreteDecorator(); void Operation(); void AddedBehavior(); protected: private: }; #endif //~_DECORATOR_H_ |
代码片断2:Decorator.cpp #include "Decorator.h" #include <iostream> Component::Component() } Component::~Component() } void Component::Operation() } ConcreteComponent::ConcreteComponent() } ConcreteComponent::~ConcreteComponent() } void ConcreteComponent::Operation() Decorator::Decorator(Component* com) Decorator::~Decorator() void Decorator::Operation() } ConcreteDecorator::ConcreteDecorator(Component* com):Decorator(com) } ConcreteDecorator::~ConcreteDecorator() } void ConcreteDecorator::AddedBehavior() this->AddedBehavior(); |
代码片断3:main.cpp #include "Decorator.h" #include <iostream> int main(int argc,char* argv[]) Decorator* dec = new ConcreteDecorator(com); dec->Operation(); delete dec; return 0; |
2.3.2 代码说明
Decorator模式很简单,代码本身没有什么好说明的。运行示例代码可以看到,ConcreteDecorator给ConcreteComponent类添加了动作AddedBehavior。
2.4 讨论
Decorator模式和Composite模式有相似的结构图,其区别在Composite模式已经详细讨论过了,请参看相应文档。另外GoF在《设计模式》中也讨论到Decorator和Proxy模式有很大程度上的相似,初学设计模式可能实在看不出这之间的一个联系和相似,并且它们在结构图上也很不相似。实际上,在本文档2.2节模式选择中分析到,让Decorator直接拥有一个ConcreteComponent的引用(指针)也可以达到修饰的功能,大家再把这种方式的结构图画出来,就和Proxy很相似了!
Decorator模式和Proxy模式的相似的地方在于它们都拥有一个指向其他对象的引用(指针),即通过组合的方式来为对象提供更多操作(或者Decorator模式)间接性(Proxy模式)。但是他们的区别是,Proxy模式会提供使用其作为代理的对象一样接口,使用代理类将其操作都委托给Proxy直接进行。这里可以简单理解为组合和委托之间的微妙的区别了。
Decorator模式除了采用组合的方式取得了比采用继承方式更好的效果,Decorator模式还给设计带来一种“即用即付”的方式来添加职责。在OO设计和分析经常有这样一种情况:为了多态,通过父类指针指向其具体子类,但是这就带来另外一个问题,当具体子类要添加新的职责,就必须向其父类添加一个这个职责的抽象接口,否则是通过父类指针是调用不到这个方法了。这样处于高层的父类就承载了太多的特征(方法),并且继承自这个父类的所有子类都不可避免继承了父类的这些接口,但是可能这并不是这个具体子类所需要的。而在Decorator模式提供了一种较好的解决方法,当需要添加一个操作的时候就可以通过Decorator模式来解决,你可以一步步添加新的职责。