## 模式定義
迭代器模式提供一種方法順序訪問一個聚合對象中的各個元素,而又不暴露其內部的表示。
迭代器模式讓我們能游走于聚合內的每一個元素,而又不暴露其內部的表示。把游走的任務放在迭代器上,而不是聚合上。這樣簡化了聚合的接口和實現,也讓責任各得其所。
## 模式結構:

? ? ? 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**
**請按任意鍵繼續. . .**
## 設計原則的應用:
??? ? 設計原則:一個類應該只有一個引起變化的原因。這個原則告訴我們盡量讓一個類保持單一責任。如果一個類具有兩個以上改變的原因,那么這會使將來該類的變化率上升。