设计模式之迭代器模式

一、模式动机

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

运行结果:

这里写图片描述

四、分析总结

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值