一、 迭代器(Iterator)模式
迭代器是針對集合對象而生的,對於集合對象而言,必然涉及到集合元素的添加刪除操作,同時也肯定支持遍歷集合元素的操作,我們此時可以把遍歷操作也放在集合對象中,但這樣的話,集合對象就承擔太多的責任了,面向對象設計原則中有一條是單一職責原則,所以我們要盡可能地分離這些職責,用不同的類去承擔不同的職責。迭代器模式就是用迭代器類來承擔遍歷集合元素的職責。
迭代器模式提供了一種方法順序訪問一個聚合對象(理解為集合對象)中各個元素,而又無需暴露該對象的內部表示,這樣既可以做到不暴露集合的內部結構,又可讓外部代碼透明地訪問集合內部的數據。
二、 迭代器模式的結構
既然,迭代器模式承擔了遍歷集合對象的職責,則該模式自然存在2個類,一個是聚合類,一個是迭代器類。在面向對象涉及原則中還有一條是針對接口編程,所以,在迭代器模式中,抽象了2個接口,一個是聚合接口,另一個是迭代器接口,這樣迭代器模式中就四個角色了,具體的類圖如下所示:
從上圖可以看出,迭代器模式由以下角色組成:
三、 迭代器模式的實現
// 抽象聚合類
using System;
public interface IListCollection
{
Iterator GetIterator();
}
// 迭代器抽象類
public interface Iterator
{
bool MoveNext();
Object GetCurrent();
void Next();
void Reset();
}
// 具體聚合類
public class ConcreteList : IListCollection
{
readonly int[] _collection;
public ConcreteList()
{
_collection = new int[] { 2, 4, 6, 8 };
}
public Iterator GetIterator()
{
return new ConcreteIterator(this);
}
public int Length
{
get { return _collection.Length; }
}
public int GetElement(int index)
{
return _collection[index];
}
}
// 具體迭代器類
public class ConcreteIterator : Iterator
{
// 迭代器要集合對象進行遍歷操作,自然就需要引用集合對象
private readonly ConcreteList _list;
private int _index;
public ConcreteIterator(ConcreteList 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++;
}
}
}
// 客戶端
class Program
{
static void Main(string[] args)
{
IListCollection list = new ConcreteList();
Iterator iterator = list.GetIterator();
while (iterator.MoveNext())
{
var i = (int)iterator.GetCurrent();
Console.WriteLine(i.ToString());
iterator.Next();
}
Console.Read();
}
}
自然,上面代碼的運行結果也是對集合每個元素的輸出,具體運行結果如下所示:
2 4 6 8
四、 .NET中迭代器模式的應用
在.NET下,迭代器模式中的聚集接口和迭代器接口都已經存在了,其中IEnumerator接口扮演的就是迭代器角色,IEnumberable接口則扮演的就是抽象聚集的角色,只有一個GetEnumerator()方法,關於這兩個接口的定義可以自行參考MSDN。在.NET 1.0中,.NET 類庫中很多集合都已經實現了迭代器模式,大家可以用反編譯工具Reflector來查看下mscorlib程序集下的System.Collections命名空間下的類,這裡給出ArrayList的定義代碼,具體實現代碼可以自行用反編譯工具查看,具體代碼如下所示:
using System;
using System.Collections;
using System.Collections.Generic;
public class ArrayList : IList, ICollection, IEnumerable, ICloneable
{
// Fields
private const int DefaultCapacity = 4;
private object[] _items;
private int _size;
[NonSerialized]
private object _syncRoot;
private int _version;
public ArrayList(object[] items, int size, object syncRoot, int version)
{
_items = items;
_size = size;
_syncRoot = syncRoot;
_version = version;
}
public virtual IEnumerator GetEnumerator();
public virtual IEnumerator<> GetEnumerator(int index, int count);
// Properties
public virtual int Capacity { get; set; }
public virtual int Count { get; }
..............// 更多代碼請自行用反編譯工具Reflector查看
}
通過查看源碼你可以發現,ArrayList中迭代器的實現與我們前面給出的示例代碼非常相似。然而,在.NET 2.0中,由於有了yield return關鍵字,實現迭代器模式就更簡單了。
五、 迭代器模式的適用場景
在下面的情況下可以考慮使用迭代器模式:
六、 迭代器模式的優缺點
優點:
缺點:
七、 總結
到這裡,本博文的內容就介紹結束了,迭代器模式就是抽象一個迭代器類來分離了集合對象的遍歷行為,這樣既可以做到不暴露集合的內部結構,又可讓外部代碼透明地訪問集合內部的數據。