(1)迭代器的本质:控制访问聚合对象中的元素。迭代器能实现“无须暴露聚合对象的内部实现,就能够访问到聚合对象的各个元素的功能”,做到“透明”的访问聚合对象中的元素。注意迭代器能够即“透明”访问,又可以“控制访问”聚合对象,认识这点,对于识别和变形使用迭代器模式很有帮助。
(2)迭代器的关键思想:把对聚合对象的遍历访问从聚合对象中分离出来,放入单独的迭代器中,这样聚合对象会变得简单,而且迭代器和聚合对象可以独立地变化和发展,会大大加强系统的灵活性。
(3)迭代器的动机:
在软件构建过程中,集合对象内部结构常常变化各异。但对于这些集合对象,我们希望在不暴露其内部结构的同时,可以让外部客户代码透明地访问其中包含的元素;同时这种“透明遍历”也为“同一种算法在多种集合对象上进行操作”提供了可能。将遍历机制抽象为“迭代器对象”为“应对变化中的集合对象”提供了一种优雅的方法
(4)内部迭代器与外部迭代器
①内部迭代器:指的是由迭代器自己来控制下一个元素的步骤,即当客户端利用迭代器读取当前元素后,迭代器的当前元素自动移到一下个元素,而客户端无法干预。
②外部迭代器:则客户端控制迭代下一个元素的步骤,即客户端必须显示的next来迭代下一个元素。从总体来说外部迭代器比内部迭代器要灵活一些。这也是常见的实现方式。
迭代器模式高级应用
(1)带迭代策略的迭代器
①由于迭代器模式把聚合对象和访问聚合的机制实现了分离,因此可以在迭代器上实现不同的迭代策略,如实现过滤功能的迭代器
②在实现过滤功能的迭代器中,有两种常见的过滤情况,一是对数据整条过滤,如只能查看自己部门的数据;另一种情况是对数据进行部分过滤,如某些人不能查看工资数据。
③带迭代策略的迭代器实现的一个基本思路就是把聚合对象的聚合数据获取到并存储在迭代器中,这样迭代器就可以按照不同的策略来迭代数据了。
(2)双向迭代器:可以向前和向后遍历数据的迭代器
【编程实验】带过滤和双向遍历功能的工资查看系统
//声明文件
//********************************************************************************
//行为模式——迭代器模式
//场景:工资表数据遍历(带过滤和双向遍历功能)
#include <iostream>
#include <string>
#include <vector>
using namespace std;
//***************************辅助类*************************
class CEmpIt;
class CEmpArr;
//工资描述模型对象
class CEmpPay{
private:
string strEmp;//职工姓名
double dPay;//工资数额
public:
CEmpPay(string emp, double pay);
~CEmpPay(){cout << "~CEmppay" << endl;}
void SetEmp(string emp);
string GetEmp();
void SetPay(double pay);
double GetPay();
void DispInfo();
};
//***********************具体迭代器*****************************
//具体的迭代器对象
//用来实现访问数组的迭代接口,加入了迭代策略
//其主要思路就是在ArrayInterator中保存一份过滤后的Aggregate聚合对象数据。
class CEmpIt{
private:
CEmpArr* pArr;
int iCurr;//记录当前迭代到的位置索引
public:
CEmpIt(CEmpArr* arr);
~CEmpIt();
void First();//移动到聚合对象的第1个位置
void Last();//移动到聚合对象的最后一个位置
void Next(); //移动到聚合对象的下一个位置
void Prev();//移动到前一个位置
bool IsEOF();//判断是否到了尾部位置
bool IsBOF();//判断是否到了头部位置
//在这里对返回的数据进行过滤,比如不让查看具体的工资数据
CEmpPay* CurrItem();//获取当前元素
};
//用数组模拟具体的聚合对象
class CEmpArr{
public:
vector<CEmpPay*> vEmpPay;//聚合对象
CEmpIt* pIt;//提供创建具体迭代器的接口
public:
CEmpArr();
CEmpIt* GetIt();
int Size();//获取数量大小
void Add(CEmpPay* obj);//加入元素
CEmpPay* Get(int idx);//获取指定位置的元素
CEmpArr* NewInst();
~CEmpArr();
};
//实现文件
//******************************************************************************************
//***************************辅助类*************************
//工资描述模型对象
CEmpPay::CEmpPay(string emp, double pay){strEmp = emp; dPay = pay;}
void CEmpPay::SetEmp(string emp){strEmp = emp;}
string CEmpPay::GetEmp(){return strEmp;}
void CEmpPay::SetPay(double pay){dPay = pay;}
double CEmpPay::GetPay(){return dPay;}
void CEmpPay::DispInfo(){cout << "Emp : " << strEmp << ", Pay : " << dPay << endl;}
//***********************具体迭代器*****************************
//具体的迭代器对象
//用来实现访问数组的迭代接口,加入了迭代策略
//其主要思路就是在ArrayInterator中保存一份过滤后的Aggregate聚合对象数据。
CEmpIt::CEmpIt(CEmpArr* arr){
iCurr = 0;
pArr = arr->NewInst();//原型模式,根据agg的实际类型创建对象
//在这里先对聚合对象的数据进行过滤,比如必须在3000以上
for(int i = 0; i < arr->Size(); i++){
CEmpPay* pObj = arr->Get(i);
if(pObj->GetPay() > 3000) pArr->Add(pObj);
}
}
CEmpIt::~CEmpIt(){pArr->vEmpPay.clear(); delete pArr;}
void CEmpIt::First(){ iCurr = 0;}//移动到聚合对象的第1个位置
void CEmpIt::Last(){ iCurr = pArr->Size() - 1;}//移动到聚合对象的最后一个位置
void CEmpIt::Next(){if(iCurr < pArr->Size()) ++iCurr;} //移动到聚合对象的下一个位置
void CEmpIt::Prev(){if(iCurr > -1) --iCurr;} //移动到前一个位置
bool CEmpIt::IsEOF(){return (iCurr >= pArr->Size());}//判断是否到了尾部位置
bool CEmpIt::IsBOF(){return (iCurr < 0);}//判断是否到了头部位置
//在这里对返回的数据进行过滤,比如不让查看具体的工资数据
CEmpPay* CEmpIt::CurrItem(){//获取当前元素
CEmpPay* pObj = pArr->Get(iCurr);
pObj->SetPay(0); return pObj;
}
//用数组模拟具体的聚合对象
CEmpArr::CEmpArr(){pIt = NULL;}
CEmpIt* CEmpArr::GetIt(){
if(pIt == NULL) pIt = new CEmpIt(this);
return pIt;
}
int CEmpArr::Size(){return vEmpPay.size();}//获取数量大小
void CEmpArr::Add(CEmpPay* obj){vEmpPay.push_back(obj);}//加入元素
CEmpPay* CEmpArr::Get(int idx){ return vEmpPay[idx];}//获取指定位置的元素
CEmpArr* CEmpArr::NewInst(){ return new CEmpArr();}
CEmpArr::~CEmpArr(){
delete pIt;
if(vEmpPay.size() == 0) return;
cout << "Before deleting... size : " << vEmpPay.size() << endl;
for(vector<CEmpPay*>::iterator it = vEmpPay.begin(); it != vEmpPay.end(); ){
CEmpPay* pObj = (*it);
if(pObj != NULL){
cout << pObj->GetEmp() << endl;
delete pObj;
}
it = vEmpPay.erase(it);
}
cout << "After deleted... size : " << vEmpPay.size() << endl;
}
//测试客户端
void main()
{
CEmpArr* pArr = new CEmpArr();
//为了测试,输入些数据进去
CEmpPay* pEntity = new CEmpPay("张三", 2800); pArr->Add(pEntity);
pEntity = new CEmpPay("李四", 4800); pArr->Add(pEntity);
pEntity = new CEmpPay("王五", 7500); pArr->Add(pEntity);
pEntity = new CEmpPay("赵六", 8000); pArr->Add(pEntity);
cout << "正向遍历>>>>>>>>>>>>>>>>>>>>>>>>>>" << endl;
CEmpIt* pIt = pArr->GetIt();
pIt->First();
while(!pIt->IsEOF()){
pIt->CurrItem()->DispInfo();
pIt->Next();
}
cout << "反向遍历>>>>>>>>>>>>>>>>>>>>>>>>>>" << endl;
pIt->Last();
while(!pIt->IsBOF()){
pIt->CurrItem()->DispInfo();
pIt->Prev();
}
delete pArr;
}