设计模式-迭代器模式 C++实现

来源:互联网 发布:linux top命令详解 编辑:程序博客网 时间:2024/06/13 21:46

一个聚合对象,如一个列表(List)或者一个集合(Set),应该提供一种方法来让别人可以访问它的元素,而又不需要暴露它的内部结构。
针对不同的需要,可能还要以不同的方式遍历整个聚合对象,但是我们并不希望在聚合对象的抽象层接口中充斥着各种不同遍历的操作。
怎样遍历一个聚合对象,又不需要了解聚合对象的内部结构,还能够提供多种不同的遍历方式,这就是迭代器模式所要解决的问题。

1.模式定义

迭代器模式(Iterator Pattern) :提供一种方法来访问聚合对象,而不用暴露这个对象的内部表示,其别名为游标(Cursor)。迭代器模式是一种对象行为型模式。

2.模式结构

迭代器模式包含如下角色:

Iterator: 抽象迭代器ConcreteIterator: 具体迭代器Aggregate: 抽象聚合类ConcreteAggregate: 具体聚合类

这里写图片描述

3.代码分析

Iterator.h

template<class Item>class Iterator{public:    Iterator() {};    virtual ~Iterator() {};    virtual void first() = 0;    virtual void next() = 0;    virtual Item *curItem() = 0;    virtual bool isDone() = 0;};

ConcreteIterator.h

#pragma once#include "Iterator.h"template<class Item>class ConcreteIterator : public Iterator <Item>{public:    ConcreteIterator(Aggregate<Item> *a) :aggr(a), cur(0) {};    virtual ~ConcreteIterator() {};    virtual void first();    virtual void next();    virtual Item *curItem();    virtual bool isDone();private:    Aggregate<Item> *aggr;    int cur;};template<class Item>void ConcreteIterator<Item>::first(){    cur = 0;}template<class Item>void ConcreteIterator<Item>::next(){    if (cur < aggr->getSize())        cur++;}template<class Item>Item *ConcreteIterator<Item>::curItem(){    if (cur < aggr->getSize())    {        return &(*aggr)[cur];    }    else    {        return NULL;    }}template<class Item>bool ConcreteIterator<Item>::isDone(){    return cur >= aggr->getSize();}

Aggregate.h

#pragma once#include "Iterator.h"template<class Item>class Aggregate{public:    Aggregate() {};    virtual ~Aggregate() {};    virtual void pushData(Item item) = 0;    virtual Iterator<Item>* createIterator() = 0;    virtual Item& operator[](int index) = 0;    virtual int getSize() = 0;};                                                                                                                                                     

ConcreteAggregate.h

#pragma once#include <vector>#include "Aggregate.h"#include "ConcreteIterator.h"using namespace std;template <class Item>class ConcreteAggregate : public Aggregate<Item>{public:    ConcreteAggregate() {};    virtual ~ConcreteAggregate() {};    virtual void pushData(Item item);    virtual Iterator<Item>* createIterator();    virtual Item& operator[](int index);    virtual int getSize();private:    vector<Item> data;};template <class Item>void ConcreteAggregate<Item>::pushData(Item item){    data.push_back(item);}template <class Item>Iterator<Item>* ConcreteAggregate<Item>::createIterator(){    return new ConcreteIterator<Item>(this);}template <class Item>Item& ConcreteAggregate<Item>::operator[](int index){    return data[index];}template <class Item>int ConcreteAggregate<Item>::getSize(){    return data.size();}

测试代码:

int main(int argc, char *argv[]){    Aggregate<int> * aggr = new ConcreteAggregate<int>();    aggr->pushData(3);    aggr->pushData(2);    aggr->pushData(1);    Iterator<int> * it = aggr->createIterator();    for (it->first(); !it->isDone(); it->next())    {        std::cout << *it->curItem() << std::endl;    }    delete it;    delete aggr;}

这里写图片描述

4.模式优点

简化了遍历方式,对于对象集合的遍历,还是比较麻烦的,对于数组或者有序列表,我们尚可以通过游标来取得,但用户需要在对集合了解很清楚的前提下,自行遍历对象,但是对于hash表来说,用户遍历起来就比较麻烦了。而引入了迭代器方法后,用户用起来就简单的多了。
可以提供多种遍历方式,比如说对有序列表,我们可以根据需要提供正序遍历,倒序遍历两种迭代器,用户用起来只需要得到我们实现好的迭代器,就可以方便的对集合进行遍历了。
封装性良好,用户只需要得到迭代器就可以遍历,而对于遍历算法则不用去关心。

5.模式缺点

对于比较简单的遍历(像数组或者有序列表),使用迭代器方式遍历较为繁琐,大家可能都有感觉,像ArrayList,我们宁可愿意使用for循环和get方法来遍历集合。

6.总结

迭代器模式是与集合共生共死的,一般来说,我们只要实现一个集合,就需要同时提供这个集合的迭代器,就像java中的Collection,List、Set、Map等,这些集合都有自己的迭代器。假如我们要实现一个这样的新的容器,当然也需要引入迭代器模式,给我们的容器实现一个迭代器。

但是,由于容器与迭代器的关系太密切了,所以大多数语言在实现容器的时候都给提供了迭代器,并且这些语言提供的容器和迭代器在绝大多数情况下就可以满足我们的需要,所以现在需要我们自己去实践迭代器模式的场景还是比较少见的,我们只需要使用语言中已有的容器和迭代器就可以了。