设计模式C++实现——迭代器模式

作者:walkerkalr 和linux相关  

模式定义

        迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。

        迭代器模式让我们能游走于聚合内的每一个元素,而又不暴露其内部的表示。把游走的任务放在迭代器上,而不是聚合上。这样简化了聚合的接口和实现,也让责任各得其所。

模式结构:


        Iterator:迭代器定义访问和遍历元素的接口

        ConcreteIterator:具体迭代器实现迭代器接口;对该聚合遍历时跟踪当前位置

        Aggregate:聚合定义创建相应的迭代器对象接口

        ConcreteAggregate:具体聚合实现创建相应迭代器的接口,该操作返回ConcreteIterator的一个适当的实例。

举例:

        煎饼屋和午餐店合并后需要定制一份新的餐单,但由于煎饼屋的原菜单是用链表实现,而午餐点原菜单是用数组实现(他们的定义如下所示),所以打印新餐单的时候需要分别循环遍历原餐单中的菜单项。

//菜单项类
class MenuItem
{
public:
	MenuItem(){}
	MenuItem(string na, string descrip, double pric)
	{
		name = na;
		description = descrip;
		price = pric;
	}

	string getName()
	{
		return name;
	}

	string getDescription()
	{
		return description;
	}
	
	double getPrice()
	{
		return price;
	}
private:
	string name;
	string description;
	double price;
};
//煎饼屋餐单类
class PancakeHouseMenu
{
public:
	PancakeHouseMenu()
	{
		addItem("K&B'S Breakfase","pacakes with eggs",2.99);
		addItem("Buleberry Breakfase","pacakes with buleberries",3.99);
	}

	void addItem(string na, string descrip, double ric)
	{
		MenuItem menuItem(na,descrip,ric);
		menuItems.push_back(menuItem);
	}
	list<MenuItem> getMenuItems()
	{
		return menuItems;
	}
private:
	list<MenuItem> menuItems;
};
//午餐点餐单类
class DinerMenu
{
public:
	DinerMenu()
	{
		addItem("Vegetarian BLT", "Bacon with lettuce", 2.99);
		addItem("BLT", "Bacon with tomato", 3.99);
	}
	void addItem(string na, string descrip, double ric)
	{
		MenuItem menuItem(na,descrip,ric);
		menuItems.push_back(menuItem);
	}
	vector<MenuItem> getMenuItems()
	{
		return menuItems;
	}
private:
	vector<MenuItem> menuItems;
};
//必须调用pancakeHouseMenu.getMenuItems()和//dinerMenu.getMenuItems()来取得他们的餐单
PancakeHouseMenu pancakeHouseMenu;
list<MenuItem> breakfastItems = pancakeHouseMenu.getMenuItems();
DinerMenu dinerMenu;
vector<MenuItem> lunchItem = dinerMenu.getMenuItems();

	list<MenuItem>::iterator iter = breakfastItems.begin();
	//打印新餐单的时候需要分别循环遍历原餐单中的菜单项
	for(; iter != breakfastItems.end(); ++iter)
	{
		MenuItem menuItem = *iter;
		cout << menuItem.getName() << "	"<< menuItem.getPrice()<<"	" 
			<< menuItem.getDescription() << endl;
	}

	for(unsigned int i=0; i<lunchItem.size(); ++i)
	{
		MenuItem menuItem = lunchItem[i];
		cout << menuItem.getName() << "	"<< menuItem.getPrice()<<"	" 
			<< menuItem.getDescription() << endl;
	}
	return 0;
}


如果还有第三家餐厅加入,我们还需要第三个循环,意味着要写很多重复代码。解决方法利用迭代器模式。

UML设计:



编程实现及执行结果:

 

#include <iostream>
#include <vector>
#include <list>
#include <string>

using namespace std;

//菜单项类
class MenuItem
{
public:
	MenuItem(){}
	MenuItem(string na, string descrip, double pric)
	{
		name = na;
		description = descrip;
		price = pric;
	}

	string getName()
	{
		return name;
	}

	string getDescription()
	{
		return description;
	}
	
	double getPrice()
	{
		return price;
	}
private:
	string name;
	string description;
	double price;
};
//迭代器基类
class Iterator
{
public:
	//是否有下一个一个菜单
	virtual bool hasNext(){throw std::exception("ERROR");};
	//取下一个菜单
	virtual MenuItem next(){throw std::exception("ERROR");};
};
//煎饼屋餐单迭代器
class PancakeHouseMenuIterator : public Iterator
{
public:
	PancakeHouseMenuIterator(list<MenuItem> item)
	{
		items = item;
		iter = items.begin();
	}
	MenuItem next()
	{
		MenuItem menuItem = *iter;
		++iter;
		return menuItem;
	}

	bool hasNext()
	{
		if(iter == items.end())
		{
			return false;
		}
		else
		{
			return true;
		}
	}
private:
	list<MenuItem> items;
	list<MenuItem>::const_iterator iter;
};
//午餐店餐单迭代器
class DinerMenuIterator : public Iterator
{
public:
	DinerMenuIterator(vector<MenuItem> item):position(0)
	{
		items = item;
	}
	MenuItem next()
	{
		MenuItem menuItem = items[position];
		position = position + 1;
		return menuItem;
	}

	bool hasNext()
	{
		if(position >= items.size())
		{
			return false;
		}
		else
		{
			return true;
		}
	}
private:
	vector<MenuItem> items;
	unsigned int position;
};

//餐单基类
class Menu
{
public:
	//创建迭代器
	virtual Iterator* createIterator(){throw std::exception("ERROR");}
};



//煎饼屋餐单类
class PancakeHouseMenu : public Menu
{
public:
	PancakeHouseMenu()
	{
		addItem("K&B'S Breakfase","pacakes with eggs",2.99);
		addItem("Buleberry Breakfase","pacakes with buleberries",3.99);
	}
	//增加菜单
	void addItem(string na, string descrip, double ric)
	{
		MenuItem menuItem(na,descrip,ric);
		menuItems.push_back(menuItem);
	}
	//创建PancakeHouseMenuIterator迭代器
	Iterator* createIterator()
	{
		return new PancakeHouseMenuIterator(menuItems);
	}
private:
	list<MenuItem> menuItems;
};

//午餐点餐单类
class DinerMenu : public Menu
{
public:
	DinerMenu()
	{
		addItem("Vegetarian BLT", "Bacon with lettuce", 2.99);
		addItem("BLT", "Bacon with tomato", 3.99);
	}
	void addItem(string na, string descrip, double ric)
	{
		MenuItem menuItem(na,descrip,ric);
		menuItems.push_back(menuItem);
	}
	Iterator* createIterator()
	{
		return new DinerMenuIterator(menuItems);
	}
private:
	vector<MenuItem> menuItems;
};

//服务生类
class Waitress
{
public:
	Waitress(Menu* p_PancakeHouseMenu, Menu* p_DinerMenu)
	{
		pPancakeHouseMenu = p_PancakeHouseMenu;
		pDinerMenu = p_DinerMenu;
	}
	//打印菜单
	void printMenu()
	{
		Iterator* pPancakeHouseIterator = pPancakeHouseMenu->createIterator();
		Iterator* pDinerIterator = pDinerMenu->createIterator();

		cout << "Menu"<< endl <<"----"<<endl << "BREAKFAST" <<endl;
		printMenu(pPancakeHouseIterator);
		cout << "LUNCH" << endl;
		printMenu(pDinerIterator);
	}
	//因为抽象出迭代器,所以可以根据迭代器打印菜单
	void printMenu(Iterator* iter)
	{
		while(iter->hasNext())
		{
			MenuItem menuItem = (MenuItem)iter->next();
			cout << menuItem.getName() << "	"<< menuItem.getPrice()<<"	" 
			<< menuItem.getDescription() << endl;
		}
	}
private:
	Menu* pPancakeHouseMenu;
	Menu* pDinerMenu;
};
//客户代码
int main()
{
	Menu* pPancakeHouseMenu = new PancakeHouseMenu();
	Menu* pDinerMenu = new DinerMenu();

	Waitress waitress(pPancakeHouseMenu,pDinerMenu);
	waitress.printMenu();
	return 0;
}

执行结果:

Menu

----

BREAKFAST

K&B'SBreakfase 2.99    pacakes with eggs

BuleberryBreakfase     3.99    pacakes with buleberries

LUNCH

VegetarianBLT  2.99    Bacon with lettuce

BLT     3.99   Bacon with tomato

请按任意键继续. . .

设计原则的应用:

        设计原则:一个类应该只有一个引起变化的原因。这个原则告诉我们尽量让一个类保持单一责任。如果一个类具有两个以上改变的原因,那么这会使将来该类的变化率上升。


相关资料:

设计模式C++实现——迭代器模式来源网络,如有侵权请告知,即处理!

编程Tags: