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

一、组合(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内部机理。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值