## 模式定义
迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。
迭代器模式让我们能游走于聚合内的每一个元素,而又不暴露其内部的表示。把游走的任务放在迭代器上,而不是聚合上。这样简化了聚合的接口和实现,也让责任各得其所。
## 模式结构:
![](https://box.kancloud.cn/2016-08-30_57c545916c8cc.jpg)
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设计:
![](https://box.kancloud.cn/2016-08-30_57c54591afeb7.jpg)
## 编程实现及执行结果:
~~~
#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**
**请按任意键继续. . .**
## 设计原则的应用:
设计原则:一个类应该只有一个引起变化的原因。这个原则告诉我们尽量让一个类保持单一责任。如果一个类具有两个以上改变的原因,那么这会使将来该类的变化率上升。