设计模式之迭代器模式

来源:互联网 发布:mp3网络歌曲地址 编辑:程序博客网 时间:2024/06/05 19:24

一、模式动机

  有很多种方法可以把对象堆起来成为一个集合(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;}

运行结果:

这里写图片描述

四、分析总结

  迭代器模式提供了一种方法,可以顺序访问一个聚集对象中的元素,而又不用知道内部是如何表示的。另外,迭代器模式把元素之间游走的责任交给迭代器,而不是聚合对象。这不仅让聚合的接口和实现变得更简洁,也可以让聚合更专注在它所专注的事情上面,而不必去理会遍历的事情。

原创粉丝点击