设计模式迭代器模式

迭代器模式Iterator):

    提供一种方法顺序访问一个聚合对象中各个元素,而不暴漏该对象的内部表示。


    当你需要访问一个聚集对象,而且不管这些对象是什么都需要遍历的时候,你就应该考虑用迭代器模式。你需要对聚集有多种方式遍历时,可以考虑用迭代器模式。
为遍历不同的聚集结构提供如开始、下一个、是否结束、当前哪一项等统一的接口。
作者已经考虑废除这个模式了,因为现在很多语言已经支持迭代了,但是这个模式还是有实现的价值的,就是实现价值大于使用价值,接下来简单实现一下。

迭代器模式

.H

#pragma once
#include <list>
using namespace std;

//Iterator 迭代器抽象类
class CIterator
{
public:
	virtual void* First() = 0;
	virtual void* Next() = 0;
	virtual bool IsDone() = 0;
	virtual void* CurrentItem() = 0;
};

//Aggregate 聚集抽象类
class CAggregate
{
public:
	virtual CIterator * CreateIterator() = 0;
	virtual void Insert(void *const pNode) = 0;
	virtual void Remove(void *const pNode) = 0;
};

//ConcreteAggregate 具体聚集类 继承Aggregate
class CConcreteAggregate : public CAggregate
{
public:
	list <void*> m_pItems;
	CConcreteAggregate();
	void Clear();
	CIterator * CreateIterator();
	void Insert(void *const pNode);
	void Remove(void *const  pNode);
};

//ConcreteIterator具体迭代器类,继承Iterator
class CConcreteIterator : public CIterator
{
private:
	CConcreteAggregate *m_pAggregate;
	int m_nCurrent;
public:
	CConcreteIterator(CConcreteAggregate * pAggregate);
    void* First();
	void* Next();
	bool IsDone();
	void* CurrentItem();
};

.CPP

#include "stdafx.h"
#include "IteratorMode.h"

CConcreteAggregate::CConcreteAggregate()
{
	m_pItems.clear();
}
void CConcreteAggregate::Clear()
{
	for each(auto i in m_pItems)
	{
		delete i;
	}
}

CIterator * CConcreteAggregate::CreateIterator()
{
	return new CConcreteIterator(this);
}

void CConcreteAggregate::Insert(void *const pNode)
{
	m_pItems.push_back(pNode);
}

void CConcreteAggregate::Remove(void *const pNode)
{
	m_pItems.remove(pNode);
}


CConcreteIterator::CConcreteIterator(CConcreteAggregate * pAggregate)
{
	m_pAggregate = pAggregate;
	m_nCurrent = 0;
}

void* CConcreteIterator::First()
{
	return m_pAggregate->m_pItems.size() == 0 ? NULL : *(m_pAggregate->m_pItems.begin());
}

void* CConcreteIterator::Next()
{
	if(IsDone()) return NULL;
	int nSubscript = 0;
	m_nCurrent ++;
    for each(auto i in m_pAggregate->m_pItems)
	{
		if(nSubscript ++ == m_nCurrent + 1)
		{
			return i;
		}
	}
}

bool CConcreteIterator::IsDone()
{
	return m_nCurrent >= m_pAggregate->m_pItems.size();
}

void* CConcreteIterator::CurrentItem()
{
	int nSubscript = 0;
	for each(auto i in m_pAggregate->m_pItems)
	{
		if(nSubscript++ == m_nCurrent)
		{
			return i;
		}
	}
	return NULL;
}
客户端调用:


#include "stdafx.h"
#include "IteratorMode.h"
#include <iostream>
#include <string>
#include <windows.h>
using namespace std;

int main()
{
	CConcreteAggregate *pA = new CConcreteAggregate();
	pA->Insert(new string("node-1"));
	pA->Insert(new string("node-2"));
	string * pstr = new string("node-3");
	pA->Insert(pstr);

	CIterator *pIteratorA = new CConcreteIterator(pA);
	while(!pIteratorA->IsDone())
	{
		cout<<*((string*)pIteratorA->CurrentItem())<<endl;
	    pIteratorA->Next();
	}

	pA->Remove(pstr);
	CIterator *pIteratorB = new CConcreteIterator(pA);
	while(!pIteratorB->IsDone())
	{
		cout<<*((string*)pIteratorB->CurrentItem())<<endl;
		pIteratorB->Next();
	}
	pA->Clear();
	delete pIteratorA;
	delete pIteratorB;
	delete pstr;//*自己移除的对象该迭代器不会再clear里面进行清理内存,
	            //哎!内存谁来释放这个问题一直是一个经典的蛋疼问题,
	            //合作开发的时候一定要注意这个问题,轻则内存泄露,重则系统崩溃。
	return 0;
}

运行结果:


总结:
    在写上面代码的时候,我一直在纠结,实现迭代器为什么非要拆成两大部分,聚集抽象类和迭代抽象类,这么想的原因就是我觉得迭代本身一个简单的类就完事了,原因是我觉得核心就是这几个接口而已:

直接定义一个类,然后有一个离散化的连续存储,然后再把上面的那几个接口实现下就可以了,为什么还要多出来一个聚集类,然后自己想了一阵子,发现确实需要这个类,原因是如下几个:
1.首先迭代类本身只是为了迭代,单独成一个类封装好之后通常不会去修改,也不用关心迭代的对象的其他独有特征什么的,而聚集类是把整个存储单元进行整理在一起,同时方便内存释放等,逻辑上看着也比较清晰。
2.如果我们要扩展这个迭代器,比如增加功能A(.find功能),比如增加一个功能B(把所有元素都进行+1操作),比如增加功能C(在指定元素上进行+1)操作。其实这个时候我们也可以把A和B集成到聚集类里,然后再把C继承在迭代类里,这样相对合理,整体的操作的东西我们就放在整体管理的类,单独操作的就放在独立的类里(但是不得不说,把C加在迭代类里也不是很合适,毕竟那个类的初始目的是为了迭代)。如果这个时候我们只有一个类,把所有的东西都写在一起,内容多到一定程度的时候,就难以维护和扩展了,同时逻辑会比较乱。
原文地址:https://www.cnblogs.com/csnd/p/12062333.html