迭代器模式(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加在迭代类里也不是很合适,毕竟那个类的初始目的是为了迭代)。如果这个时候我们只有一个类,把所有的东西都写在一起,内容多到一定程度的时候,就难以维护和扩展了,同时逻辑会比较乱。