迭代器模式--《设计模式-可复用面向对象软件的基础》Erich Gamma

来源:互联网 发布:淘宝客店铺推广链接 编辑:程序博客网 时间:2024/06/05 18:49

迭代器模式

STL中使用了迭代器,本文一步一步设计迭代器并改进。

Iterator是对象行为型模式。

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

思想:将遍历机制和聚合对象相分离,从而可以定义不同迭代器来实现不同的遍历策略(如从前向后遍历元素,从后向前等等)。

优点:将聚合对象的接口简单化,不包括遍历方法;可以定义不同的迭代器来实现不同的遍历方法。

实现:一步一步改进我们的迭代器模式

(1)设计1:一个特定聚合类,对应一个访问该聚合对象的迭代器

思路:

 

缺点:需要指定特定聚合类,来创建对应的迭代器,则用户代码需要改变。如下:

    创建访问遍历列表元素的迭代器:ListIterator<int> iter (List<int> *list);

创建访问遍历向量元素的迭代器:VectorIterator<int> iter (Vector<int> *vector);

这样太麻烦了。每次都需要用户修改代码。

(2)设计2改进上述方法。在创建迭代器的时候,用户代码不需要知道创建的迭代器是访问哪一种聚合对象。即:创建迭代器的代码不依赖于具体的聚合对象。

思路:让特定的聚合对象去创建遍历自己元素的迭代器。则用户使用统一的接口创建迭代器。有两个类层次,一个是Container类层次,一个是迭代器Iterator类层次。CreateIterator方法将这两个类层次联系起来。

 

   定义聚合抽象类Container,子类有ListVector等;父类定义CreateIterator接口,让子类重新实现CreateIterator来返回相应的具体迭代器。定义抽象迭代器类Iterator,子类有ListIteratorVectorIterator。则用户可以使用统一的接口CreateIterator创建迭代器。使用方法如下:

例:List<int > list;  Container *con=&list; 

    Iterator *iter=con->CreateIterator();  delete iter;   //iter是访问list的迭代器;

Vector<int > vec;  Container *con=&vec;  

Iterator *iter=con->CreateIterator();  delete iter;   //iter访问vector的迭代器;

 缺点:CreateIterator()动态创建迭代器,则用户使用迭代器后需要自己手动释放迭代器内存,delete Iterator。如果程序异常终止或者忘记delete,则会造成内存泄露。

(3)设计3改进上述设计方法。使用迭代器的代理。

思路:我们可以借用智能指针的思路,自己再定义一个迭代器的代理,让代理负责释放迭代器占用的动态内存。这个代理在栈上分配内存,当该代理生命期结束后,系统会自动调用代理的析构函数回收内存。我们就在这个代理的析构中delete迭代器占用的内存资源。

template<typename Item>

Class IteratorPtr

{ Private: Iterator<Item>* iter;

 Public:

IteratorPtr(Iterator<Item>* it){ iter=it; }

~IteratorPtr(){delete iter;}

Iterator<Item>* operator->(){ return iter;}

Iterator<Item> operator.(){ return *iter;}

IteratorPtr& operator=(const IteratorPtr&);

IteratorPtr(const IteratorPtr& );

}

使用如下:

List<int > list;  Container *con=&list; IteratorPtr<int> it( con->CreateIterator() ); 不需delete

Vector<int > vec;  Container *con=&vec; IteratorPtr<int> it( con->CreateIterator() ); 不需delete

(4)设计4:上述实现的迭代器都是一个外部迭代器,每次遍历一个元素;有时候我们需要一个迭代器能自己遍历完所有容器元素。这样的迭代器就是内部迭代器。

思路:在迭代器的内部调用外部迭代器。