15 迭代器(Iterator)模式

迭代器模式

1.1 分类

(对象)行为型

1.2 提出问题

两个餐厅要合并,虽然两家菜单系统类似,但底层使用的数据结构不同,如何能让客户端方便的遍历。

1.3 解决方案

提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部表示。

1.4 实现类图

在这里插入图片描述

  1. 迭代器(Iterator)接口声明了遍历集合所需的操作:获取下一个元素、是否有下一个元素等。
  2. 具体迭代器(Concrete Iterators)实现遍历集合的一种特定算法。迭代器对象必须跟踪自身遍历的进度。
  3. 集合(Collection)接口声明获取与集合兼容的迭代器的方法。
  4. 具体集合(Concrete Collections)在客户端请求迭代器时返回一个特定的具体迭代器类实体。
  5. 客户端(Client)通过集合和迭代器的接口与两者进行交互,允许同一客户端代码使用各种不同的集合和迭代器。

1.5 示例代码

#include <iostream>
#include <string>
#include <list>

template <class T, class U>
class Iterator {
public:
    typedef typename std::list<T>::iterator Pointer;
    Iterator(U* p_container, bool reverse = false) : m_pContainer(p_container) {}
    void first() {
        m_iter = m_pContainer->m_data.begin();
    }
    void next() {
        m_iter++;
    }
    bool isDone() {
        return (m_iter == m_pContainer->m_data.end());
    }
    Pointer current() {
        return m_iter;
    }
private:
    U* m_pContainer;
    Pointer m_iter;
};

template <class T>
class Container {
    friend class Iterator<T, Container>;
public:
    Iterator<T, Container>* createIterator() {
        return new Iterator<T, Container>(this);
    }
    void add(T data) {
        m_data.push_back(data);
    }
private:
    std::list<T> m_data;
};

class MenuItem {
public:
    ~MenuItem(){}
    virtual void setData(std::string data1, std::string data2 = "") = 0;
    virtual std::string data() const = 0;
};
class Beverage : public MenuItem {
public:
    ~Beverage() {}
    Beverage(std::string data1, std::string data2) : m_data1(data1), m_data2(data2) {}
    virtual void setData(std::string data1, std::string data2) override {
        m_data1 = data1;
        m_data2 = data2;
    }
    virtual std::string data() const override {
        return m_data1 + "_" + m_data2;
    }
private:
    std::string m_data1;
    std::string m_data2;
};
class Pizza : public MenuItem {
public:
    ~Pizza() {}
    Pizza(std::string data) : m_data(data) {}
    virtual void setData(std::string data, std::string data2 = "") override {
        m_data = data;
    }
    virtual std::string data() const override {
        return m_data;
    }
private:
    std::string m_data;
};

template<class T>
void clientCode(T* iter) {
    for (iter->first(); !iter->isDone(); iter->next()) {
        std::cout << iter->current()->data() << std::endl;
    }
}
int main()
{
    Container<Beverage> beverageMenu;
    Beverage coffee("美式", "咖啡"), bubbleTea("珍珠", "奶茶");
    beverageMenu.add(coffee);
    beverageMenu.add(bubbleTea);

    Container<Pizza> pizzaMenu;
    Pizza a("意大利香肠"), b("海鲜披萨"),c("榴莲披萨");
    pizzaMenu.add(a);
    pizzaMenu.add(b);
    pizzaMenu.add(c);
    //遍历菜单
    std::cout << "Iterator用于遍历Beverage菜单:\n";
   /*Iterator<Beverage, Container<Beverage>>**/ 
    auto it = beverageMenu.createIterator();
    clientCode(it);
    std::cout << "Iterator用于遍历Pizza菜单:\n";
    auto it2 = pizzaMenu.createIterator();
    clientCode(it2);

    delete it;
    delete it2;
}

1.6 举个栗子

迭代器模式用于遍历一个封装了访问好友关系功能的特殊集合。该集合提供使用不同方式遍历档案资料的多个迭代器。
在这里插入图片描述

1.7 总结

1.7.1 优点

  1. 单一职责原则。将庞大的遍历算法代码抽取为独立的类。
  2. 开闭原则。可实现新型的集合和迭代器,无需修改现有代码。
  3. 可以并行遍历同一集合,因为每个迭代器对象都包含其自身的遍历状态。 并可以暂停遍历并在需要的时候继续。

1.7.2 缺点

  1. 如果程序只与简单的集合进行交互,应用该模式可能适得其反。
  2. 对于某些特殊集合,使用迭代器可能比直接遍历的效率低。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值