您的位置:首页 > 其它

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

2012-11-06 10:58 417 查看
/***********************************

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: