一、 迭代器(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關鍵字,實現迭代器模式就更簡單了。
五、 迭代器模式的適用場景
在下面的情況下可以考慮使用迭代器模式:
六、 迭代器模式的優缺點
優點:
缺點:
七、 總結
到這裡,本博文的內容就介紹結束了,迭代器模式就是抽象一個迭代器類來分離了集合對象的遍歷行為,這樣既可以做到不暴露集合的內部結構,又可讓外部代碼透明地訪問集合內部的數據。