一、动机(Motivate)
在软件构建过程中,集合对象内部结构常常变化各异。但对于这些集合对象,我们希望在不暴露其内部结构的同时,可以让外部客户代码透明地访问其中包含的元素;同时这种“透明遍历”也为“同一种算法在多种集合对象上进行操作”提供了可能。
使用面向对象技术将这种遍历机制抽象为“迭代器对象”为“应对变化中的集合对象”提供了一种优雅的方式。
二、意图(Intent)
提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。 ——《设计模式》GoF
三、结构图
四、模式的组成
从迭代器模式的结构图可以看出,它涉及到四个角色,它们分别是:
(1)、抽象迭代器(Iterator):抽象迭代器定义了访问和遍历元素的接口,一般声明如下方法:用于获取第一个元素的first(),用于访问下一个元素的next(),用于判断是否还有下一个元素的hasNext(),用于获取当前元素的currentItem(),在其子类中将实现这些方法。
(2)、具体迭代器(ConcreteIterator):具体迭代器实现了抽象迭代器接口,完成对集合对象的遍历,同时在对聚合进行遍历时跟踪其当前位置。
(3)、抽象聚合类(Aggregate):抽象聚合类用于存储对象,并定义创建相应迭代器对象的接口,声明一个createIterator()方法用于创建一个迭代器对象。
(4)、具体聚合类(ConcreteAggregate):具体聚合类实现了创建相应迭代器的接口,实现了在抽象聚合类中声明的createIterator()方法,并返回一个与该具体聚合相对应的具体迭代器ConcreteIterator实例。
五、迭代器模式的代码实现
迭代器模式在现实生活中也有类似的例子,比如:在部队中,我们可以让某一队伍当中的某人出列,或者让队列里面的每个人依次报名,其实这个过程就是一个遍历的过程。
// 客户端(Client) static void Main(string[] args) { Iterator iterator; ITroopQueue list = new ConcreteTroopQueue(); iterator = list.GetIterator(); while (iterator.MoveNext()) { string ren = (string)iterator.GetCurrent(); Console.WriteLine(ren); iterator.Next(); } Console.Read(); } // 部队队列的抽象聚合类--该类型相当于抽象聚合类Aggregate public interface ITroopQueue { Iterator GetIterator(); } // 迭代器抽象类 public interface Iterator { bool MoveNext(); Object GetCurrent(); void Next(); void Reset(); } //部队队列具体聚合类--相当于具体聚合类ConcreteAggregate public sealed class ConcreteTroopQueue : ITroopQueue { private string[] collection; public ConcreteTroopQueue() { collection = new string[] { "黄飞鸿", "方世玉", "洪熙官", "严咏春" }; } public Iterator GetIterator() { return new ConcreteIterator(this); } public int Length { get { return collection.Length; } } public string GetElement(int index) { return collection[index]; } } // 具体迭代器类 public sealed class ConcreteIterator : Iterator { // 迭代器要集合对象进行遍历操作,自然就需要引用集合对象 private ConcreteTroopQueue _list; private int _index; public ConcreteIterator(ConcreteTroopQueue list) { _list = list; _index = 0; } public bool MoveNext() { if (_index < _list.Length) { return true; } return false; } public Object GetCurrent() { return _list.GetElement(_index); } public void Reset() { _index = 0; } public void Next() { if (_index < _list.Length) { _index++; } } }
六、迭代器模式的实现要点:
1、迭代抽象:访问一个聚合对象的内容而无需暴露它的内部表示。
2、迭代多态:为遍历不同的集合结构提供一个统一的接口,从而支持同样的算法在不同的集合结构上进行操作。
3、迭代器的健壮性考虑:遍历的同时更改迭代器所在的集合结构,会导致问题。
迭代器模式的优点:
(1)、迭代器模式使得访问一个聚合对象的内容而无需暴露它的内部表示,即迭代抽象。
(2)、迭代器模式为遍历不同的集合结构提供了一个统一的接口,从而支持同样的算法在不同的集合结构上进行操作
迭代器模式的缺点:
(1)、迭代器模式在遍历的同时更改迭代器所在的集合结构会导致出现异常。所以使用foreach语句只能在对集合进行遍历,不能在遍历的同时更改集合中的元素。
迭代器模式的使用场景:
(1)、访问一个聚合对象的内容而无需暴露它的内部表示。
(2)、支持对聚合对象的多种遍历。
(3)、为遍历不同的聚合结构提供一个统一的接口(即, 支持多态迭代)。
七、.NET 中迭代器模式的实现
在mscorlib程序集里有这样一个命名空间,该命名空间就是:System.Collections,在该命名空间里面早已有了迭代器模式的实现。对于聚集接口和迭代器接口已经存在了,其中IEnumerator扮演的就是迭代器的角色,它的实现如下:
public interface IEnumerator { object Current { get; } bool MoveNext(); void Reset(); }
属性Current返回当前集合中的元素,Reset()方法恢复初始化指向的位置,MoveNext()方法返回值true表示迭代器成功前进到集合中的下一个元素,返回值false表示已经位于集合的末尾。能够提供元素遍历的集合对象,在.Net中都实现了IEnumerator接口。
IEnumerable则扮演的就是抽象聚集的角色,只有一个GetEnumerator()方法,如果集合对象需要具备跌代遍历的功能,就必须实现该接口。
public interface IEnumerable { IEumerator GetEnumerator(); }
抽象聚合角色(Aggregate)和抽象迭代器角色(Iterator)分别是IEnumerable接口和IEnumerator接口,具体聚合角色(ConcreteAggregate)有Queue类型, BitArray等类型,