设计模式——迭代器(Iterator)

来源:互联网 发布:挖掘社交网络 中文版 编辑:程序博客网 时间:2024/05/17 04:55

定义:

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


使用:

在软件构建过程中, 集合对象内部结构常常变化各异。但对于这些集合对象,我们希望在不暴露其内部结构的同时,可以让外部客户代码透明地访问其中包含的元素;同时这种“透明遍历”也为“同一种算法在多种结合对象上进行操作”提供了可能。使用面向对象技术,将这种遍历机制抽象为“迭代器对象”,为“应对变化中的集合对象”提供了一种优雅的遍历方式。


UML类图:

19. C++实现Behavioral - Iterator模式 - 玄机逸士 - 玄机逸士博客 

要点:

- 迭代抽象: 访问一个聚合对象的内容,而无需暴露其内部表示。

- 迭代多态: 为遍历不同的集合结构提供一个统一的接口,从而支持同样的算法在不同的集合结构上进行操作。

- 迭代器通常不应该修改所在集合的结构,如删除其中一个元素,也就是迭代器通常是只读的,但未必尽然。

 

实例:

19. C++实现Behavioral - Iterator模式 - 玄机逸士 - 玄机逸士博客 


// Iterator.h#include <string>#include <iostream>#include <memory>using namespace std; // 这个类将作为集合中的元素class Person{private:         string name;         string mobilephone;public:         // 由于ConcreteCollection类的构造函数中的collection = new T[100];这一句,因此,Person类         // 必须提供缺省构造函数         Person()         {         }          Person(const string name, const string mobilephone)         {                   this->name = name;                   this->mobilephone = mobilephone;         }          ~Person()         {                   //由于Person类的析构函数会被调用很多次,所以就把下面一行注释了,以便使得输出更整洁一些                   //cout << "in the destructor of Person..." << endl;         } public:         // 显示元素本身的内容         string to_string()         {                   string str = name + "\t" + mobilephone;                   return str;         }}; // 这是迭代器所必须实现的接口template <typename T>class IIterator{public:         virtual T next() = 0;                                 // 取出下一个元素         virtual bool has_next() = 0;                  // 遍历完了吗?如果遍历完,则返回false;否则,返回true public:         virtual ~IIterator()         {                   cout << "in the destructor of IIterator..." << endl;         }}; // 定义IIterable接口,所有的欲使用迭代器的集合类,都必须继承它template <typename T>class IIterable{public:         virtual auto_ptr<IIterator<T> > get_iterator() = 0;                  // 获取迭代器(智能指针)public:         virtual ~IIterable()         {                   cout << "in the destructor of IIterable..." << endl;         }}; // 具体集合类template <typename T>class ConcreteCollection : public IIterable<T>{private:         int index;         T *collection; public:         ConcreteCollection()         {                   collection = new T[100];                   index = 0;         }          // 增加一个元素         void add_element(T obj)         {                   collection[index++] = obj;         }          // 获取一个指定位置的元素         T get_element_at(int i)         {                   return collection[i];         }          // 获取集合中元素的个数         int get_size()         {                   return index;         }          // 获取迭代器(智能指针)         auto_ptr<IIterator<T> > get_iterator()         {                   auto_ptr<IIterator<T> > temp(new ConcreteIterator<Person>(this));                   return temp;         } public:         ~ConcreteCollection()         {                   delete [] collection;    // 对应构造函数中的collection = new T[100];                   cout << "in the destructor of ConcreteCollection..." << endl;         }}; // 具体迭代器类template <typename T>class ConcreteIterator : public IIterator<T>{private:         int index;         ConcreteCollection<T> *collection; public:         ConcreteIterator(IIterable<T> *iterable)         {                   index = 0;                   collection = dynamic_cast<ConcreteCollection<T> *>(iterable);                                       // 向下转型,即将基类的指针转换为派生类的指针,此处使用dynamic_cast                                       // 是为了进行严格的类型检查。一般而言,向下转型时不安全的,因此要使                                       // 用dynamic_cast         }          bool has_next()         {                   if(0 == collection->get_size())                   {                            return false;                   }                    if(index < collection->get_size())                   {                            return true;                   }                   else                   {                            return false;                   }         }          T next()         {                   return collection->get_element_at(index++);         } public:         ~ConcreteIterator()         {                   cout << "in the destructor of ConcreteIterator..." << endl;         }}; // Iterator.cpp#include "Iterator.h" int main(int argc, char **argv){         ConcreteCollection<Person> *collection = new ConcreteCollection<Person>();          collection->add_element(Person("玄机逸士", "13800000001"));         collection->add_element(Person("上官天野", "13800000002"));         collection->add_element(Person("黄药师   ", "13800000003"));         collection->add_element(Person("欧阳锋   ", "13800000004"));         collection->add_element(Person("段王爷   ", "13800000005"));         collection->add_element(Person("洪七公   ", "13800000006"));          auto_ptr<IIterator<Person> > iter(collection->get_iterator());          while(iter->has_next())         {                   cout << (iter->next()).to_string() << endl;         }          delete collection;          return 0;}

运行结果:

玄机逸士   13800000001

上官天野   13800000002

黄药师       13800000003

欧阳锋       13800000004

段王爷       13800000005

洪七公       13800000006

in the destructor of ConcreteCollection...

in the destructor of IIterable...

in the destructor of ConcreteIterator...

in the destructor of IIterator...


Iterator模式实现需注意的要点:

1. 两个重要接口,即IIterable和IIterator,它们分别对应的具体类ConcreteCollection和ConcreteIterator。本质上而言ConcreteCollection中存放的是数据,ConcreteIterator中实现的是遍历的方法。

2. ConcreteCollection中的getIterator()方式的实现技巧。即

         return new ConcreteIterator(this);

    ConcreteCollection将自己(当然也包括ConcreteCollection中包含的数据)通过ConcreteIterator的构造函数,传递给ConcreteIterator,然后ConcreteIterator利用已实现的方法对其进行遍历。

3. 模板类的应用。上述实现由于使用了模板,因此ConcreteCollection中的元素也可以是除Person类之外的其他类型。