问题
iterator模式应该是最为熟悉的模式了,最简单的证明就是在实现Composite模式,Flyweight模式,Observer模式中就直接用到了STL提供的Iterator来遍历Vector或者List数据结构。
Iterator模式也正是用来解决对一个聚合对象的遍历问题,将对聚合的遍历封装到一个类中进行,这样就避免了暴露这个聚合对象的内部表示的可能。
iterator迭代器模式
提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。
小demo
iterator.h
#ifndef ITERATOR_H
#define ITERATOR_H
typedef int DATA;
class Iterater;
// 容器的抽象基类
class Aggregate
{
public:
virtual ~Aggregate(){}
virtual Iterater* CreateIterater(Aggregate *pAggregate) = 0;
virtual int GetSize() = 0;
virtual DATA GetItem(int nIndex) = 0;
};
// 迭代器的抽象基类
class Iterater
{
public:
virtual ~Iterater(){}
virtual void First() = 0;
virtual void Next() = 0;
virtual bool IsDone() = 0;
virtual DATA CurrentItem() = 0;
};
// 一个具体的容器类,这里是用数组表示
class ConcreateAggregate : public Aggregate
{
public:
ConcreateAggregate(int nSize);
virtual ~ConcreateAggregate();
virtual Iterater* CreateIterater(Aggregate *pAggregate);
virtual int GetSize();
virtual DATA GetItem(int nIndex);
private:
int m_nSize;
DATA *m_pData;
};
// 访问ConcreateAggregate容器类的迭代器类
class ConcreateIterater : public Iterater
{
public:
ConcreateIterater(Aggregate* pAggregate);
virtual ~ConcreateIterater(){}
virtual void First();
virtual void Next();
virtual bool IsDone();
virtual DATA CurrentItem();
private:
Aggregate *m_pConcreateAggregate;
int m_nIndex;
};
#endif
iterator.cpp
#include <iostream>
#include "Iterator.h"
ConcreateAggregate::ConcreateAggregate(int nSize)
: m_nSize(nSize)
, m_pData(NULL)
{
m_pData = new DATA[m_nSize];
for (int i = 0; i < nSize; ++i)
{
m_pData[i] = i;
}
}
ConcreateAggregate::~ConcreateAggregate()
{
delete [] m_pData;
m_pData = NULL;
}
Iterater* ConcreateAggregate::CreateIterater(Aggregate *pAggregate)
{
return new ConcreateIterater(this);
}
int ConcreateAggregate::GetSize()
{
return m_nSize;
}
DATA ConcreateAggregate::GetItem(int nIndex)
{
if (nIndex < m_nSize)
{
return m_pData[nIndex];
}
else
{
return -1;
}
}
ConcreateIterater::ConcreateIterater(Aggregate* pAggregate)
: m_pConcreateAggregate(pAggregate)
, m_nIndex(0)
{
}
void ConcreateIterater::First()
{
m_nIndex = 0;
}
void ConcreateIterater::Next()
{
if (m_nIndex < m_pConcreateAggregate->GetSize())
{
++m_nIndex;
}
}
bool ConcreateIterater::IsDone()
{
return m_nIndex == m_pConcreateAggregate->GetSize();
}
DATA ConcreateIterater::CurrentItem()
{
return m_pConcreateAggregate->GetItem(m_nIndex);
}
main.cpp
#include "Iterator.h"
#include <iostream>
int main()
{
Aggregate* pAggregate = new ConcreateAggregate(4);
Iterater* pIterater = new ConcreateIterater(pAggregate);
for (; false == pIterater->IsDone(); pIterater->Next())
{
std::cout << pIterater->CurrentItem() << std::endl;
}
system("pause");
return 0;
}
迭代器模式适用性
- 当集合背后为复杂的数据结构,且你希望对客户端隐藏其复杂性时 (出于使用便利性或安全性的考虑),可以使用迭代器模式。
- 使用该模式可以减少程序中重复的遍历代码。
- 如果你希望代码能够遍历不同的甚至是无法预知的数据结构,可以使用迭代器模式。
实现方式
- 声明迭代器接口。 该接口必须提供至少一个方法来获取集合中的下个元素。 但为了使用方便, 你还可以添加一些其他方法, 例如获取前一个元素、 记录当前位置和判断迭代是否已结束。
- 声明集合接口并描述一个获取迭代器的方法。 其返回值必须是迭代器接口。 如果你计划拥有多组不同的迭代器, 则可以声明多个类似的方法。
- 为希望使用迭代器进行遍历的集合实现具体迭代器类。 迭代器对象必须与单个集合实体链接。 链接关系通常通过迭代器的构造函数建立。
- 在你的集合类中实现集合接口。 其主要思想是针对特定集合为客户端代码提供创建迭代器的快捷方式。 集合对象必须将自身传递给迭代器的构造函数来创建两者之间的链接。
- 检查客户端代码, 使用迭代器替代所有集合遍历代码。 每当客户端需要遍历集合元素时都会获取一个新的迭代器。
与其他模式的关系
- 可以使用迭代器模式来遍历组合模式树。
- 可以同时使用工厂方法模式和迭代器来让子类集合返回不同类型的迭代器,并使得迭代器与集合相匹配。
- 可以同时使用备忘录模式和迭代器来获取当前迭代器的状态,并且在需要的时候进行回滚。
- 可以同时使用访问者模式和迭代器来遍历复杂数据结构,并对其中的元素执行所需操作,即使这些元素所属的类完全不同。