设计模式之实现迭代器模式

/***********************************

baseobject.h

***********************************/

#pragma once
#include <iostream>
#include <string>
#include <vector>
#include "CIterator.h"
#define MAX_ARRAY_SIZE 100
using namespace std;

//前置定义
class CIteratorInterface;
class CElectricIterator;

//////////////////////////////////////////
//在C++对象不像在Java中一样,有统一的基类Ojbect,
//所以,我们在这里为所有要出售的对象设定一个对象的基类
class CBaseObjectMenuItem
{
private:
 string m_Name;
 float  m_Price;
public:
 CBaseObjectMenuItem(string name, float price) : m_Name(name), m_Price(price){}

 virtual float getPrice() {
  return m_Price;
 }
 
 virtual string getName(){
  return m_Name;
 }

 void showInformation(){
  cout<<"Name : "<<m_Name<<"\t\t\t";
  cout<<"Price : "<<m_Price<<endl;
 }
};

////////////////////////////////////////////
//我这里先给出一个菜单类的接口,
//这里简单处理菜单项,假设菜单项总是由一个名字和一个价格所决定的
class CSaleMenu
{
public:
 virtual void addMenuItem(string Name, float Price) = 0;

 virtual CIteratorInterface* createIterator() = 0;
};

/////////////////////////////////////////
//电器菜单类,用数组实现
//其中有一个方法可以用来创建一个迭代器
class CElectricMenu : public CSaleMenu
{
private:
 unsigned long       m_totalItems;

 //我这里也用指针的原因是为了防止对象切片(slicing)
 //因为现在这里还是非常简单的情况就是,菜单对像还只是一个基类的直接对象
 //如果这个对象是一个菜单项基类的派生类的对象时,切记:千万不要以数组的多态方式来处理
 //这样会导致切片问题,可详见more efficient C++的相关章节
 CBaseObjectMenuItem* m_ItemPointers[MAX_ARRAY_SIZE];

public:
 CElectricMenu() : m_totalItems(0){}

 void addMenuItem(string Name, float Price){
  m_ItemPointers[m_totalItems++] = new CBaseObjectMenuItem(Name, Price);
 }

 inline unsigned long getTotalMenuItems(){
  return m_totalItems;
 }

 CBaseObjectMenuItem** getMenu(){
  return m_ItemPointers;
 }

 CIteratorInterface* createIterator();


 ~CElectricMenu(){
  for(unsigned long i = 0; i < m_totalItems; i++)
   delete m_ItemPointers[i];
 }
};

/////////////////////////////////////////
//食品菜单菜,用vector实现
class CFoodMenu : public CSaleMenu
{
private:
 //我这里也用指针的原因是为了防止对象切片(slicing)
 //因为现在这里还是非常简单的情况就是,菜单对像还只是一个基类的直接对象
 //如果这个对象是一个菜单项基类的派生类的对象时,切记:千万不要以数组的多态方式来处理
 //这样会导致切片问题,可详见more efficient C++的相关章节
 vector<CBaseObjectMenuItem*> m_ItemPointer;
public:
 void addMenuItem(string Name, float Price){
  m_ItemPointer.push_back(new CBaseObjectMenuItem(Name, Price));
 }

 vector<CBaseObjectMenuItem*>& getMenu(){
  return m_ItemPointer;
 }

 CIteratorInterface* createIterator();

 ~CFoodMenu(){
  for(int i = 0; i < static_cast<int>(m_ItemPointer.size()); i++){
   delete m_ItemPointer[i];
  }
  m_ItemPointer.clear();
 }
};

/***********************************************

CIterator.h

***********************************************/

#pragma once
#include <iostream>
#include <string>
#include <vector>
#include "baseobject.h"
using namespace std;

class CBaseObjectMenuItem;


//////////////////////////////////////////
//迭代器的接口,这是每个迭代器都要实现的.
class CIteratorInterface
{
public:
 virtual bool hasNext() = 0;
 virtual CBaseObjectMenuItem* next() = 0;

 virtual ~CIteratorInterface() {}
};


/////////////////////////////////////////
//这是一个用于数组接口的迭代器,我们实现了电器数组的迭代
//用数据实现
class CElectricIterator : public CIteratorInterface
{
private:
 unsigned long m_totalItems;
 CBaseObjectMenuItem** m_MenuItem;

 unsigned long m_currentIt;

public:
 CElectricIterator(CBaseObjectMenuItem** inMenu, unsigned long inTI);

 bool hasNext();

 CBaseObjectMenuItem* next();
};

/////////////////////////////////////////
//这是一个用于vector接口的迭代器,我们实现了食物vector的迭代
//用vector实现
class CFoodIterator : public CIteratorInterface
{
private:
 vector<CBaseObjectMenuItem*>& m_MenuItem;

 unsigned long m_currentIt;
public:
 CFoodIterator(vector<CBaseObjectMenuItem*>& inItemList);

 bool hasNext();

 CBaseObjectMenuItem* next();
};

/******************************************

CMenuShower.h

*******************************************/

#pragma once
#include <iostream>
#include "baseobject.h"
#include "CIterator.h"


//////////////////////////////////////////////
//是时候来做一个显然菜单的类的
//这个类是与具体菜单元素存放方式无关的(已经解耦了)
//当要具体类时,就创建一个iterator,切记,用完后要删除
class CMenuShower
{
private:
 CSaleMenu* m_Menu1; //电子产品类的menu
 CSaleMenu* m_Menu2; //食品类的menu

 //可以像下面这样来管理所有菜单项
 //vector<CSaleMenu*> m_Menus;

public:
 CMenuShower(CSaleMenu* inElecMenu, CSaleMenu* inFoodMenu) :
 m_Menu1(inElecMenu), m_Menu2(inFoodMenu)
 {

 }

private:
 static void PrintSingleIterator(CIteratorInterface* it){
  if(!it)
   return;
  while(it->hasNext()){
   CBaseObjectMenuItem* tmp = it->next();
   tmp->showInformation();
  }
 }

public:

 //哈哈。这下总算是成功与菜单实现解耦了。
 //如果没有解耦的话,我们还需要知道不同人实现的放在数据的方法,然后分别处理。
 //在使用了迭代器模式后,我们就需要知道迭代器模式的接品即可。
 void PrintAllMenuItems(){
  //电器类商品, “电器类菜单说: 你打印吧,不要管我是怎么实现的”
  cout<<"[电器类商品]"<<endl;
  PrintSingleMenu(m_Menu1);

  //食物类商品 “食物类菜单说: 你打印吧,你也不要管我是怎么实现的”
  cout<<"[食物类商品]"<<endl;
  PrintSingleMenu(m_Menu2);
 }

public:
 static void PrintSingleMenu(CSaleMenu* menu)
 {
  if(!menu)
   return;
  CIteratorInterface* it = menu->createIterator();
  PrintSingleIterator(it);
  delete it;
 }
};

/*****************************************

baseobject.cpp

******************************************/

#include "baseobject.h"
#include "CIterator.h"


CIteratorInterface* CElectricMenu::createIterator()
{
 //注意这里new了一个iterator
 //在调用的地方,调用完了之后,一定要把这块内存释放掉。
 return static_cast<CIteratorInterface*>(
  new CElectricIterator(m_ItemPointers, m_totalItems));
}


CIteratorInterface* CFoodMenu::createIterator()
{
 //注意这里new了一个iterator
 //在调用的地方,调用完了之后,一定要把这块内存释放掉。
 return static_cast<CIteratorInterface*>(
  new CFoodIterator(m_ItemPointer));
}

/******************************************

Citerator.cpp

******************************************/

#include "CIterator.h"
#include "baseobject.h"

/////////////////////////////////////////
//这是一个用于数组接口的迭代器,我们实现了电器数组的迭代
//用数据实现
//实现部分
CElectricIterator::CElectricIterator(CBaseObjectMenuItem** inMenu, unsigned long inTI)
: m_MenuItem(inMenu), m_totalItems(inTI), m_currentIt(0){

}

bool CElectricIterator::hasNext()
{
 return m_currentIt < m_totalItems ? true : false;
}

CBaseObjectMenuItem* CElectricIterator::next(){
 if(m_currentIt < m_totalItems)
  return m_MenuItem[m_currentIt++];
 return NULL;
}


/////////////////////////////////////////
//这是一个用于vector接口的迭代器,我们实现了食物vector的迭代
//用vector实现
//实现部分
CFoodIterator::CFoodIterator(vector<CBaseObjectMenuItem*>& inItemList)
: m_MenuItem(inItemList), m_currentIt(0){

}

bool CFoodIterator::hasNext()
{
 return m_currentIt < m_MenuItem.size() ? true : false;
}

CBaseObjectMenuItem* CFoodIterator::next(){
 if(m_currentIt < m_MenuItem.size())
  return m_MenuItem[m_currentIt++];
 return NULL;
}

/***************************************************

testiteratorPattern.cpp

***************************************************/

/*
 设计模式: 迭代器模式

 提供一种方法顺序访问一个聚合对象的各个元素 
 首先,迭代器这个方法根本不管聚合究竟是由数组还是由Array或者Vector来保存的.
 其次,迭代器模式把在元素之间遍历的责任交给迭代器,而不是某种特殊的聚合对象.

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
这个程序运用迭代器模式来遍历一些菜单项
在程序里有两个菜单项,
  一个是电子产品的菜单项  用数据实现
   一个是食品的菜单项      用vector实现

现在有一个终端机,并不知道两个菜单项的内在数据的具体存储和实现方式,但需要给客户显现数据的内容.
所以,我在这里使用了迭代器模式,把迭代过程进行封装.

CIterator为迭代器的基类

在这个迭代器模式的例子中Menu子类的createIterator()是这个模式的精髓。
这个成员返回一个所有封装的迭代器的基类接口.所以使用者就不必要去关心返回的
迭代器的内部数据存储方式
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

by 何戬, hejian@cad.zju.edu.cn
*/
#include <iostream>
#include "CMenuShower.h"
using namespace std;

int main()
{
 CElectricMenu* elecMenu = new CElectricMenu();
 elecMenu->addMenuItem("诺基亚E71", 2300.0f);
 elecMenu->addMenuItem("诺基亚N29", 2120.0f);
 CFoodMenu*     foodMenu = new CFoodMenu;
 foodMenu->addMenuItem("KFC全家套餐", 66.0f);
 foodMenu->addMenuItem("原味吮指鸡块", 7.5f);

 CMenuShower* ms = new CMenuShower(elecMenu, foodMenu);
 ms->PrintAllMenuItems();

 delete foodMenu;
 delete elecMenu;

 return 0;
}

原文地址:https://www.cnblogs.com/skyofbitbit/p/2756566.html