【转】设计模式学习笔记(8)-组合
组合(Composite)模式还是比较重要的,何谓组合?在Word中有这样一个命令

这里的组合和设计模式中的组合是一样的意思。我们都知道在word中将一些对象组合以后这些对象就可以视作一个对象,可以放大缩小移动等,和那些基本的线段、矩形、椭圆等图元没什么两样。这就是组合模式所要达到的目的。其意图:将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。
这样一来可以大大简化客户的操作,求同存异,使得程序的编写变得简单。
从类图上来看,组合模式十分类似于数据结构中的树形结构,学过数据结构的都知道,树型结构有两种节点:叶节点和其它节点。叶节点是没有子节点的,本例中的组合模式中的叶节点就是那些基本图元,而其它节点则是基本图元的组合,他们具有基本图元所拥有的所有性质,但也包括自己独有的性质主要是对子节点的操作。
类图:
这个例子中,Picture就是一个组合对象,而Graphic是所有对象的父类。Picture里面可以存储多个Graphic对象,可以是Line,Rectangle甚至是Picture自己。对这个例子进一步抽象:
这里就很清楚了,我们只有两种对象:叶子对象和组合对象。而它们都属于组件(Component)。
从这个例子我们写出一点框架代码:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
class Component {public: virtual void draw() = 0; virtual void add(Component* comp) { } virtual Component* getComponent(int n){ return 0; }};class Leaf1 : public Component{public: void draw() { cout << "Draw a leaf1" << endl; }};class Leaf2 : public Component{public: void draw() { cout << "Draw a leaf2" << endl; }};class Composite : public Component {private: vector<Component*>* _compList;public: Composite() { _compList = new vector<Component*>(); } void draw() { for(vector<Component*>::iterator it = _compList->begin(); it != _compList->end(); it++) { (*it)->draw(); } } void add(Component* comp) { _compList->push_back(comp); } Component* getComponent(int n) { return _compList->at(n); }}; |
这里有两个叶子,Leaf1和Leaf2,注意叶子节点没有重载父类中的add和getComponent方法,这点会在后来介绍。还有一个组合类,Composite,里面维持着一个Component列表,调用draw方法
时就对该列表中的所有对象逐个调用draw方法。
main函数里这样写道:
|
1
2
3
4
5
6
7
8
9
10
|
Component* cpn = new Composite();cpn->add(new Leaf1);cpn->add(new Leaf2);Component* c = new Composite();c->add(new Leaf2);c->add(new Leaf2);cpn->add(c);cpn->draw(); |
这意思很明了了,不用介绍。最终输出为:
|
1
2
3
4
|
Draw a leaf1Draw a leaf2Draw a leaf2Draw a leaf2 |
结果正是我们想要的。
注意在main函数中我们想操作叶子对象一样操作组合对象,使得添加、修改等操作十分统一,体现出来组合模式的威力。
我们回到刚才所说的问题上:叶子节点不应该add等方法而组合对象有这些方法,应该如何对待?我们使用了比较胖的接口,把这些方法放到父类Component中,这其实违反了设计原则中的
一个类只能定义那些对它的子类有意义的操作。这里不得已而未知,应为我们不能将叶子与组合分离出来,否则这个设计模式就毫无意义。为了达到统一的操作体验我们抛弃了安全性(叶
子中可能会调用add方法导致出错)而选择了透明性(打通叶子和组合对象的操作)。在面向对象程序设计中,我们经常要面临这样的抉择,关键原则是:选取最有效的方法,而不是墨守成规。
最后我们来看看组合模式的适用性:
- 想表示对象的部分-整体层次
- 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象
组合模式往往和Iterator、Visitor、Flyweight、Decorator等模式一起使用,主要用在GUI设计等方面。
posted on 2013-03-05 14:41 TheKingOfKingFish 阅读(136) 评论(0) 收藏 举报
浙公网安备 33010602011771号