您的位置:首页 > 其它

“设计模式”学习之四:组合(结构型)与迭代器(行为型)

2011-08-07 23:21 761 查看
一、组合(Composite)
1、引言
看看树形结构,一些结点是叶结点(没有子结点),另一些可能还有子结点。组合模式用于构造这种基本对象和组合对象的“部分-整体”层次结构。其中,基本对象可以被组合成组合对象,而组合对象可以被递归组合成更复杂的组合对象。而对于基本对象和组合对象,用户可以一致使用。

2、一般思路
下图中,Leaf类中的int _numLeaf; 成员变量是为了区分实例化第几个基本对象(功能详见下节代码实例)。
Composite类中的vector <Component *>_comVector;用以存贮子部件,也可用Array、List、树、hash表等数据结构。
Composite::Operation()中将引入迭代器,用以遍历子部件。而Add/Remove/GetChild()都是为了管理子部件。



3、典型代码
依据上图类关系,编写简单实例完整代码如下:
// composite.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <vector>
#include <iostream>
#include <conio.h>
using namespace std;

class Component
{
public:
Component(){}
virtual ~Component(){}
virtual void Operation() = 0;//遍历子部件
virtual void Add(Component*){}//管理子部件
virtual void Remove(Component*){}//管理
virtual Component* GetChild(int index){return 0;}//获取某个子部件
};

class Leaf : public Component
{
public:
Leaf(int numLeaf){_numLeaf = numLeaf;}
~Leaf(){}
void Operation(){cout<< "Leaf "<<_numLeaf<<" operation..."<<endl;}
int _numLeaf;//为了区分是第几个基本对象
};

class Composite : public Component
{
public:
vector <Component *>_comVector;//以存贮子部件,也可用Array、List、树、hash表等数据结构
Composite(){}
~Composite(){}
Component* GetChild(int index){return _comVector[index];}
void Operation()
{
//引入迭代器实现按顺序访问子部件
vector <Component *>:: iterator _comIterator = _comVector.begin();
for (; _comIterator != _comVector.end(); _comIterator++)
{
(*_comIterator) -> Operation();
}
}
void Add(Component* com)
{
_comVector.push_back(com);
}
void Remove(Component* com)
{
//		_comVector.erase(&com);
}

};
int _tmain(int argc, _TCHAR* argv[])
{
Leaf * aLeaf0 = new Leaf(0);
Leaf * aLeaf1 = new Leaf(1);

Composite *aComposite = new Composite();
aComposite->Add(aLeaf0);
aComposite->Add(aLeaf1);
aComposite->Operation();//内部实现遍历
cout<<endl;

Component	*aComponent = aComposite->GetChild(0);
aComponent->Operation();
aComponent = aComposite->GetChild(1);
aComponent->Operation();

_getch();/*等待按键继续*/
return 0;
}


代码运行情况如下:



4、应用提示
(1)共享组件可以节约存贮,享元Flyweight模式可以奏效。
(2)Composite可以用多种数据结构存贮子部件。当然,也可以应用解释器Interpreter模式,使用变量对应各节点,从而不用使用通用数据结构。

(3)组合经常和装饰者一块用,此时,装饰父类也必须声明Add/Remove/GetChild操作。
(4)组合模式是用“单一责任”设计原则来获取透明性——客户对叶节点与组合一视同仁,这样会损失部分操作“安全性”,比如需要警惕叶节点不能执行Add。

二、迭代器(Iterator,别名“游标”Cursor)
1、引言
对于一个聚合对象(如List、vector、自定义的组合类等等),如果想遍历其内部各个元素,又不暴露其内部结构,抑或需要不同的方式遍历它,甚至可能需要同时进行多个遍历。可以将对它的遍历访问功能抽离出来,封装到迭代器中。

2、一般思路
图中给出了迭代器Iterator的最小接口:First、Next、IsDone、CurrentItem四个。
Aggregate类即是需要迭代遍历的聚合类。



3、典型代码
////////////////////////////////////////////////
// "Iterator.h"
//
#ifndef _ITERATOR_H_
#define _ITERATOR_H_

typedef int Object;
class Iterator;

class Aggregate
{
public:
Aggregate(){}
virtual ~Aggregate(){}
virtual Iterator* CreateIterator() = 0;
virtual Object GetItem(int)=0;
virtual int GetSize()=0;
};

class ConcreteAggregate : public Aggregate
{
const static int SIZE = 5;
Object _object[SIZE];

public:
ConcreteAggregate()
{
for(int i=0; i<SIZE; i++)
_object[i] = i;
}
~ConcreteAggregate(){}
Iterator* CreateIterator();
Object GetItem(int index)
{
if(index < this->GetSize())
return _object[index];
else
return -1;
}
int GetSize(){return SIZE;}
};

class Iterator
{
public:
Iterator(){}
virtual ~Iterator(){}
virtual void First() = 0;
virtual void Next() = 0;
virtual bool IsDone() = 0;
virtual Object CurrentItem() = 0;
};

class ConcreteIterator : public Iterator
{
public:
Aggregate * _aggregate;
int _index;

ConcreteIterator(Aggregate *aggregate, int index=2)
{
//假设默然从第三个聚合对象开始索引
this->_aggregate = aggregate;
this->_index = index;
}
virtual ~ConcreteIterator(){}

void First()
{
_index = 0;
}
void Next()
{
if(_index < _aggregate->GetSize())
_index++;
}
bool IsDone()
{
return (_index == _aggregate->GetSize());
}
Object CurrentItem()
{
return _aggregate->GetItem(_index);
}
};

#endif //~_ITERATOR_H_


////////////////////////////////////////////////
// Iterator.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include <conio.h>
#include "Iterator.h"

using namespace std;

Iterator* ConcreteAggregate::CreateIterator()
{
return new ConcreteIterator(this);
}

int _tmain(int argc, _TCHAR* argv[])
{
Aggregate * aAggregate = new ConcreteAggregate();
//	Iterator *aIterator = new ConcreteIterator(aAggregate);
Iterator *aIterator = aAggregate->CreateIterator();//工厂方法

aIterator->First();//从第一个聚合对象开始索引
for(; !aIterator->IsDone(); aIterator->Next())
cout<<aIterator->CurrentItem()<<endl;

_getch();/*等待按键继续*/
return 0;
}


输出情况如下图:若无“aIterator->First();”,则输出为“2 3 4”。(从第三个聚合对象开始)



4、应用提示
(1)如果需要针对不同的聚合对象动态创建不同的迭代器,需要Factory Method模式
(2)迭代器常常在其内部存储一个备忘录Memento用以捕获一个迭代状态。
(3)在C++标准模板库STL中,迭代器容器container
(包括:向量vector、双端队列deque、表list、队列queue、堆栈stack、集合set、多重集合multiset、映射map、多重映射multimap)和算法(有大约100个实现算法的模版函数,功能涉及比较、交换、查找、遍历、复制、修改、移除、反转、排序、合并等等)的黏合剂。
(4)空迭代器NullIterator用于处理边界条件,它总是表明已经完成了遍历,通过IsDone()中返回true,或者hasNext()返回false。
附:STL学习资料
关于STL的介绍:点击打开链接
百度百科:点击打开链接
《Effective STL》Scott Meyers著,50条有效使用STL的经验。
《STL源码剖析》侯捷著,挖掘STL内部机理。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: