一、模式动机
有很多种方法可以把对象堆起来成为一个集合(collection)。可以把它们放进数组、堆栈、列表或是散列表(Hashtable)中。如果想遍历这些对象而且无法窥视存储对象的方法,就需要迭代器模式。
二、模式定义
迭代器模式(Iterator Pattern)提供了一种方法顺序访问一个聚合对象中的各个元素,而不是暴露其内部的表示。集合(collection)是指一群对象,其存储方式可以是各式各样的数据结构,例如:列表、数组等,有时候也被称为聚合(aggregate)。UML图如下:
迭代器模的角色有如下:
● 迭代器角色(Iterator):负责定义访问和遍历元素的接口。
● 具体迭代器角色(Concrete Iterator):实现迭代器的接口,并要记录遍历中的当前位置。
● 集合角色(Aggregate):负责定义创建具体迭代器角色的接口。
● 具体集合角色(Concrete Aggregate):实现创建具体迭代器角色的接口
三、模式示例
对象村的早餐店和午餐餐厅合并了,但是它们菜单使用不同数据结构表示,早餐店使用列表,午餐厅使用数组,如图代码所示。如何遍历每份菜单上的项目?
C++代码实现:
#include <string>
#include <list>
#include <iostream>
using namespace std;
//菜单项
class MenuItem
{
public:
MenuItem()
{
}
MenuItem(string name, string description, bool vegetarian, double price)
{
name_ = name;
description_ = description;
vegetarian_ = vegetarian;
price_ = price;
}
~MenuItem()
{
}
string GetName() const { return name_; }
string GetDescripition() const { return description_; }
bool IsVegetarian() const { return vegetarian_; }
double GetPrice() const { return price_; }
private:
string name_;
string description_;
bool vegetarian_;
double price_;
};
//迭代器基类
class Iterator
{
public:
//是否有下一个菜单
virtual bool HasNext() = 0;
//取下一个菜单
virtual MenuItem Next() = 0;
};
//煎饼屋餐单迭代器
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(MenuItem* items[], int size) :position(0), size_(size)
{
this->items = items;
position = 0;
}
MenuItem Next()
{
MenuItem menuItem = *(items[position]);
position += 1;
return menuItem;
}
bool HasNext()
{
if ((position >= size_) || (items[position] == NULL))
{
return false;
}
else
{
return true;
}
}
private:
MenuItem** items;
unsigned int size_;
unsigned int position;
};
//餐单基类
class Menu
{
public:
//创建迭代器
virtual Iterator* createIterator(){ throw std::exception("ERROR"); }
};
//煎饼屋菜单
class PancakeHouseMenu :public Menu
{
public:
PancakeHouseMenu();
~PancakeHouseMenu();
void AddItem(string name, string description, bool vegetarian, double price)
{
MenuItem menuItem(name, description, vegetarian, price);
menuItems_.push_back(menuItem);
}
list<MenuItem> GetMenuItems() { return menuItems_; }
Iterator* createIterator(){ return new PancakeHouseMenuIterator(this->GetMenuItems()); }
private:
list<MenuItem> menuItems_;
};
PancakeHouseMenu::PancakeHouseMenu()
{
AddItem("K&B's Pancake Breakfast", "Pancakes with scrambled eggs, and toast", true, 2.99);
AddItem("Regular Pancake Breakfast", "Pancakes with fried eggs, sausage", false, 2.99);
AddItem("Blueberry Pancakes", "Pancakes made with fresh blueberries", true, 3.49);
AddItem("Waffles", "with you choice of blueberries or strawberries", true, 3.59);
}
PancakeHouseMenu::~PancakeHouseMenu()
{
}
const int MAX_ITEMS = 6;
class DinerMenu :public Menu
{
public:
DinerMenu();
~DinerMenu();
void AddItem(string name, string description, bool vegetarian, double price)
{
MenuItem* menuItem = new MenuItem(name, description, vegetarian, price);
if (numberOfItems >= MAX_ITEMS)
{
cout << "Sorry, menu is full! Can't add item to menu" << endl;
}
else
{
menuItems_[numberOfItems] = menuItem;
numberOfItems += 1;
}
}
MenuItem** GetMenuItems()
{
return menuItems_;
}
Iterator* createIterator()
{
return new DinerMenuIterator(GetMenuItems(), MAX_ITEMS);
}
private:
int numberOfItems;
MenuItem* menuItems_[MAX_ITEMS];
};
DinerMenu::DinerMenu()
:numberOfItems(0)
{
for (unsigned int i = 0; i < MAX_ITEMS; i++)
{
menuItems_[i] = NULL;
}
AddItem("Vegetarian BLT", "(Fakin) Bacon with lettuce & tomato on whole wheat", true, 2.99);
AddItem("BLT", "Bacon with lettuce & tomato on whole wheat", false, 2.99);
AddItem("Soup of the day", "Soup of the day, with a side of potato salad", false, 3.29);
AddItem("Hotdog", "a hot dog, with saurkraut,relish,onions,topped with cheese", false, 3.05);
}
DinerMenu::~DinerMenu()
{
}
class Waitess
{
public:
Waitess(PancakeHouseMenu* pancake_house_menu, DinerMenu* diner_menu);
~Waitess();
void printMenus()
{
Iterator* pancake_iterator = pancake_house_menu_->createIterator();
Iterator* diner_iterator = diner_menu_->createIterator();
printMenu(pancake_iterator);
cout << "+++++++++++++" << endl;
printMenu(diner_iterator);
}
private:
PancakeHouseMenu* pancake_house_menu_;
DinerMenu* diner_menu_;
void printMenu(Iterator* iteror)
{
while (iteror->HasNext())
{
MenuItem menu_item = iteror->Next();
cout << menu_item.GetName() << endl;
cout << menu_item.GetDescripition() << endl;
cout << menu_item.GetPrice() << endl;
}
}
};
Waitess::Waitess(PancakeHouseMenu* pancake_house_menu, DinerMenu* diner_menu)
:pancake_house_menu_(pancake_house_menu),
diner_menu_(diner_menu)
{
}
Waitess::~Waitess()
{
}
int _tmain(int argc, _TCHAR* argv[])
{
PancakeHouseMenu* pancakeHouseMenu = new PancakeHouseMenu;
DinerMenu* dinerMenu = new DinerMenu;
Waitess waitess(pancakeHouseMenu, dinerMenu);
waitess.printMenus();
system("pause");
return 0;
}
运行结果:
四、分析总结
迭代器模式提供了一种方法,可以顺序访问一个聚集对象中的元素,而又不用知道内部是如何表示的。另外,迭代器模式把元素之间游走的责任交给迭代器,而不是聚合对象。这不仅让聚合的接口和实现变得更简洁,也可以让聚合更专注在它所专注的事情上面,而不必去理会遍历的事情。
1万+

被折叠的 条评论
为什么被折叠?



