设计模式C++实现——迭代器模式
模式定义
迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。
迭代器模式让我们能游走于聚合内的每一个元素,而又不暴露其内部的表示。把游走的任务放在迭代器上,而不是聚合上。这样简化了聚合的接口和实现,也让责任各得其所。
模式结构:
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
请按任意键继续. . .
设计原则的应用:
设计原则:一个类应该只有一个引起变化的原因。这个原则告诉我们尽量让一个类保持单一责任。如果一个类具有两个以上改变的原因,那么这会使将来该类的变化率上升。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。