迭代器模式简介
在C++标准库中,有专门的迭代器的额库,这里的迭代器模式与标准库中的迭代器功能差不多,都是对一个包含有许多个对象实例的集合进行访问和获取,另外要取集合的首位元素,末位元素,在某个位置的元素等。
针对这种集合对象的遍历,迭代器模式是一种很有效的解决方案,在实际工作中使用频率也很高。
迭代器模式:提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。
迭代器模式结构
迭代器模式结构中包含聚合和迭代器两个层次的结构。为方便扩展,迭代器模式常常和工厂方法模式结合。由图可知,迭代器模式有以下几个角色:
- Iterator(抽象迭代器):声明了访问和遍历聚合对象元素的接口,如first()方法用于访问聚合对象中第一个元素,next()方法用于访问下一个元素,hasNext()判断是否还有下一个元素,currentItem()方法用于获取当前元素。
- ConcreteIterator(具体迭代器):实现抽象迭代器声明的方法,通常具体迭代器中会专门用一个变量(称为游标)来记录迭代器在聚合对象中所处的位置。
- Aggregate(抽象聚合类):用于存储和管理元素对象,声明一个创建迭代器的接口,其实是一个抽象迭代器工厂的角色。
- ConcreteAggregate(具体聚合类):实现了方法createIterator(),该方法返回一个与该具体聚合类对应的具体迭代器ConcreteIterator的实例。
迭代器模式代码实例
#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;
};
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;
};
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;
}
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;
}
迭代器模式总结
优点:
- 支持以不同的方式遍历一个聚合对象,在同一个聚合对象上可以定义多个遍历方式。
- 简化了聚合类,使得聚合类的职责更加单一;
- 迭代器模式中引入抽象层,易于增加新的迭代器类,便于扩展,符合开闭原则。
缺点:
- 将聚合类中存储对象和管理对象的职责分离,增加新的聚合类时同样需要考虑增加对应的新的迭代器类,类的个数成对增加,不利于系统管理和维护;
- 设计难度较大,需要充分考虑将来系统的扩展。
适用环境:
以下场景可以考虑使用迭代器模式:
- 访问一个聚合对象而无需暴露它的内部结构;
- 需要为一个聚合对象提供多种遍历方法。