一、定义
迭代器( Iterator)模式,又叫做游标( Cursor)模式。 GOF 给出的定义为:提供一种方法访问一个容器( container)对象中各个元素,而又不需暴露该对象的内部细节。
从定义可见,迭代器模式是为容器而生。很明显,对容器对象的访问必然涉及到遍历算法。你可以一股脑的将遍历方法塞到容器对象中去;或者根本不去提供什么遍历算法,让使用容器的人自己去实现去吧。这两种情况好像都能够解决问题。然而在前一种情况,容器承受了过多的功能,它不仅要负责自己“容器”内的元素维护(添加、删除等等),而且还要提供遍历自身的接口;而且由于遍历状态保存的问题,不能对同一个容器对象同时进行多个遍历。第二种方式倒是省事,却又将容器的内部细节暴露无遗。而迭代器模式的出现,很好的解决了上面两种情况的弊端。
二、结构
先来看下迭代器模式的真面目吧:
1) 迭代器角色( Iterator):迭代器角色负责定义访问和遍历元素的接口。
2) 具体迭代器角色( ConcreteIterator):具体迭代器角色要实现迭代器接口,并要记录遍历中的当前位置。
3) 容器角色( Container):容器角色负责提供创建具体迭代器角色的接口。
4) 具体容器角色( Concrete Container):具体容器角色实现创建具体迭代器角色的接口——这个具体迭代器角色于该容器的结构相关。
三、实现
#include <iostream>
using namespace std;
//容器角色
typedef struct tagNode
{
int value;
tagNode *pNext;
}Node;
//具体容器(用链表代替)
class JTList
{
public:
JTList() : m_pHead(NULL), m_pTail(NULL){};
JTList(const JTList &);
~JTList();
JTList &operator=(const JTList &);
long GetCount() const;
Node *Get(const long index) const;
Node *First() const;
Node *Last() const;
bool Includes(const int &) const;
void Append(const int &);
void Remove(Node *pNode);
void RemoveAll();
private:
Node *m_pHead;
Node *m_pTail;
long m_lCount;
};
//迭代器角色
class Iterator
{
public:
virtual void First() = 0;
virtual void Next() = 0;
virtual bool IsDone() const = 0;
virtual Node *CurrentItem() const = 0;
};
JTList::~JTList()
{
Node *pCurrent = m_pHead;
Node *pNextNode = NULL;
while (pCurrent)
{
pNextNode = pCurrent->pNext;
delete pCurrent;
pCurrent = pNextNode;
}
}
long JTList::GetCount()const
{
return m_lCount;
}
Node *JTList::Get(const long index) const
{
// The min index is 0, max index is count - 1
if (index > m_lCount - 1 || index < 0)
{
return NULL;
}
int iPosTemp = 0;
Node *pNodeTemp = m_pHead;
while (pNodeTemp)
{
if (index == iPosTemp++)
{
return pNodeTemp;
}
pNodeTemp = pNodeTemp->pNext;
}
return NULL;
}
Node *JTList::First() const
{
return m_pHead;
}
Node *JTList::Last() const
{
return m_pTail;
}
bool JTList::Includes(const int &value) const
{
Node *pNodeTemp = m_pHead;
while (pNodeTemp)
{
if (value == pNodeTemp->value)
{
return true;
}
pNodeTemp = pNodeTemp->pNext;
}
return false;
}
void JTList::Append(const int &value)
{
// Create the new node
Node *pInsertNode = new Node;
pInsertNode->value = value;
pInsertNode->pNext = NULL;
// This list is empty
if (m_pHead == NULL)
{
m_pHead = m_pTail = pInsertNode;
}
else
{
m_pTail->pNext = pInsertNode;
m_pTail = pInsertNode;
}
++m_lCount;
}
void JTList::Remove(Node *pNode)
{
if (pNode == NULL || m_pHead == NULL || m_pTail == NULL)
{
return;
}
if (pNode == m_pHead) // If the deleting node is head node
{
Node *pNewHead = m_pHead->pNext;
m_pHead = pNewHead;
}
else
{
// To get the deleting node's previous node
Node *pPreviousNode = NULL;
Node *pCurrentNode = m_pHead;
while (pCurrentNode)
{
pPreviousNode = pCurrentNode;
pCurrentNode = pCurrentNode->pNext;
if (pCurrentNode == pNode)
{
break;
}
}
// To get the deleting node's next node
Node *pNextNode = pNode->pNext;
// If pNextNode is NULL, it means the deleting node is the tail node, we should change the m_pTail pointer
if (pNextNode == NULL)
{
m_pTail = pPreviousNode;
}
// Relink the list
pPreviousNode->pNext = pNextNode;
}
// Delete the node
delete pNode;
pNode = NULL;
--m_lCount;
}
void JTList::RemoveAll()
{
delete this;
}
//具体迭代器角色
class JTListIterator : public Iterator
{
public:
JTListIterator(JTList *pList) : m_pJTList(pList), m_pCurrent(NULL){}
virtual void First();
virtual void Next();
virtual bool IsDone() const;
virtual Node *CurrentItem() const;
private:
JTList *m_pJTList;
Node *m_pCurrent;
};
void JTListIterator::First()
{
m_pCurrent = m_pJTList->First();
}
void JTListIterator::Next()
{
m_pCurrent = m_pCurrent->pNext;
}
bool JTListIterator::IsDone() const
{
return m_pCurrent == m_pJTList->Last()->pNext;
}
Node *JTListIterator::CurrentItem() const
{
return m_pCurrent;
}
int main()
{
JTList *pJTList = new JTList;
pJTList->Append(10);
pJTList->Append(20);
pJTList->Append(30);
pJTList->Append(40);
pJTList->Append(50);
pJTList->Append(60);
pJTList->Append(70);
pJTList->Append(80);
pJTList->Append(90);
pJTList->Append(100);
Iterator *pIterator = new JTListIterator(pJTList);
// Print the list by JTListIterator
for (pIterator->First(); !pIterator->IsDone(); pIterator->Next())
{
cout<<pIterator->CurrentItem()->value<<"->";
}
cout<<"NULL"<<endl;
// Test for removing
Node *pDeleteNode = NULL;
for (pIterator->First(); !pIterator->IsDone(); pIterator->Next())
{
pDeleteNode = pIterator->CurrentItem();
if (pDeleteNode->value == 100)
{
pJTList->Remove(pDeleteNode);
break;
}
}
// Print the list by JTListIterator
for (pIterator->First(); !pIterator->IsDone(); pIterator->Next())
{
cout<<pIterator->CurrentItem()->value<<"->";
}
cout<<"NULL"<<endl;
delete pIterator;
delete pJTList;
return 0;
}
四、 适用情况
由上面的讲述,我们可以看出迭代器模式给容器的应用带来以下好处:1) 支持以不同的方式遍历一个容器角色。根据实现方式的不同,效果上会有差别。
2) 简化了容器的接口。
3) 对同一个容器对象,可以同时进行多个遍历。因为遍历状态是保存在每一个迭代器对象中的。
由此也能得出迭代器模式的适用范围:
1) 访问一个容器对象的内容而无需暴露它的内部表示。
2) 支持对容器对象的多种遍历。
3) 为遍历不同的容器结构提供一个统一的接口(多态迭代)。