设计人员使用数据结构(如:数组、链表、哈希表)来组织程序中的数据。迭代器设计模式可以在不了解数据结构行为(如遍历数据结构、或者删除数据结构中的元素)或者数据结构如何保存数据的情况下,就可以允许对象访问数据结构中的对象。遍历数据结构与访问它的元素的命令保存在一个名叫迭代器的单个对象中。每个数据结构都能建立一个迭代器,每个迭代器实现共同接口的方法:遍历数据结构和访问它的数据。一个对象可以用相同的方式遍历两个不同结构的数据结构,如链表和哈希表,这是因为两个数据结构包含着属于同一个类的迭代器对象,而这个类实现共同的接口。Java在java.util包中提供了接口Iterator.
意图:
提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示。
动机:
一个聚合对象,如列表(list),应该提供一种方法来让别人可以访问它的元素,而又不需要暴露它的内部结构。此外针对不同的需要,可能要以不同的方式遍历这个列表。但是即使可以预见到所需的那些遍历操作,你可能也不希望列表的接口中充斥着各种不同遍历的操作。有时还可能需要在同一个列表上同时进行多个遍历。
迭代器模式可以帮你解决所有这些问题。这一问题的关键思想是将对列表的访问和遍历从列表对象中分离出来并放入一个迭代器(iterator)对象中。迭代器类定义了一个访问该列表元素的接口。迭代器对象复杂跟踪当前的元素;即,它知道哪些元素已经遍历过了。
一个列表(List)类,需要一个列表迭代器类(ListIterator)。在实例化列表迭代器之前,必须提供待遍历的列表。一旦有了该列表迭代器的实例,就可以顺序访问列表中的各个元素。
将遍历机制与列表独享分离使我们可以定义不同的迭代器来实现不同的遍历策略,而无需在列表接口中列举它们。过滤列表迭代器可能只访问那些满足特定过滤约束条件的元素。
注意迭代器和列表是耦合在一起的,而且客户对象必须知道遍历的是一个列表而不是其他聚合结构。最好能有一种办法使得不需改变客户代码即可改变该聚合类。可以通过将迭代器的概念推广到多态迭代来达到这个目标。例如,假定我们还有一个列表的特殊实现,比如SkipList,SkipList具有一种类似于平衡树性质的随机数据结构。我们希望我们的代码对List和SkipList对象都适用。首先,定义一个抽象列表类AbstractList,它提供操作列表的公共接口。类似地,我们也需要一个抽象的迭代器类Iterator,它定义公共的迭代接口。然后我们可以为每个不同的列表实现定义具体的Iterator子类。这样迭代机制就与具体的聚合类无关了。
余下的问题是如何创建迭代器。既然要使这些代码不依赖于具体的列表子类,就不能仅仅简单地实例化一个特定的类,而要让列表对象负责创建相应的迭代器。这需要列表对象提供CreateIterator这样的操作,客户请求调用该操作以获得一个迭代器对象。
适用性:
迭代器模式可用来:1,访问一个聚合对象内容而无需暴露它的内部表示。2,支持对聚合对象的多种遍历。3,为遍历不同的聚合结构提供一个统一的接口(即,支持多态迭代)。
实现:
定义抽象List:
template <class Item> class AbstractList {
public:
virtual Iterator<Item>* CreateIterator() const = 0;
//...
};
具体list定义:
template<class Item>
class List : public AbstractList{
public:
Iterator<Item>* List<Item>::CreateIterator() const; //覆盖父类的方法
};
template <class Item> Iterator<Item>* List<Item>::CreateIterator() const {
return new LIstIterator<Item>(this);
}
迭代器接口的实现:
template <class Item>
class Iterator {
public:
virtual viod First() = 0;
virtual void Next() = 0;
virtual bool IsDone() const = 0;
virtual Item CurrentItem() const = 0;
protected:
Iterator();
};
迭代器子类的实现
template<class Item>
class ListIterator : public Iterator<Item> {
public:
ListIterator(const List<Item>* aList);
virtual void First();
virtual void Next();
virtual bool IsDone() const;
virtual Item currentItem() const;
private:
const List<Item>* _list;
long _current;
};
ListLiterator的实现简单直接。它存储List和列表当前位置的索引_current.