標籤:
一、引言
在上篇博文中分享了我對命令模式的理解,命令模式主要是把行為進行抽象成命令,使得要求者的行為和接受者的行為形成低耦合。在一章中,將介紹一下迭代器模式。下面廢話不多說了,直接進入本博文的主題。
二、迭代器模式的介紹
迭代器是針對集合對象而生的,對於集合對象而言,必然涉及到集合元素的添加刪除操作,同時也肯定支援遍曆集合元素的操作,我們此時可以把遍曆操作也放在集合對象中,但這樣的話,集合對象就承擔太多的責任了,物件導向設計原則中有一條是單一職責原則,所以我們要儘可能地分離這些職責,用不同的類去承擔不同的職責。迭代器模式就是用迭代器類來承擔遍曆集合元素的職責。
2.1 迭代器模式的定義
迭代器模式提供了一種方法順序訪問一個彙總對象(理解為集合對象)中各個元素,而又無需暴露該對象的內部表示,這樣既可以做到不暴露集合的內部結構,又可讓外部代碼透明地訪問集合內部的資料。
2.2 迭代器模式的結構
既然,迭代器模式承擔了遍曆集合對象的職責,則該模式自然存在2個類,一個是彙總類,一個是迭代器類。在物件導向涉及原則中還有一條是針對介面編程,所以,在迭代器模式中,抽象了2個介面,一個是彙總介面,另一個是迭代器介面,這樣迭代器模式中就四個角色了,具體的類圖如下所示:
從可以看出,迭代器模式由以下角色群組成:
- 迭代器角色(Iterator):迭代器角色負責定義訪問和遍曆元素的介面
- 具體迭代器角色(Concrete Iteraror):具體迭代器角色實現了迭代器介面,並需要記錄遍曆中的當前位置。
- 彙總角色(Aggregate):彙總角色負責定義獲得迭代器角色的介面
- 具體彙總角色(Concrete Aggregate):具體彙總角色實現彙總角色介面。
2.3 迭代器模式的實現
介紹完迭代器模式之後,下面就具體看看迭代器模式的實現,具體實現代碼如下:
// 抽象彙總類 public interface IListCollection { Iterator GetIterator(); }字型 // 迭尋找/替換代器抽象類別 public interface Iterator { bool MoveNext(); 字型大小Object GetCurrent(); void Next(); void Reset(); } // 具體彙總類 public class ConcreteList : IListCollection { 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 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) { Iterator iterator; IListCollection list = new ConcreteList(); iterator = list.GetIterator(); while (iterator.MoveNext()) { int i = (int)iterator.GetCurrent(); Console.WriteLine(i.ToString()); iterator.Next(); } Console.Read(); } }
自然,上面代碼的運行結果也是對集合每個元素的輸出,具體運行結果如所示:
三、.NET中迭代器模式的應用
在.NET下,迭代器模式中的聚集介面和迭代器介面都已經存在了,其中IEnumerator介面扮演的就是迭代器角色,IEnumberable介面則扮演的就是抽象聚集的角色,只有一個GetEnumerator()方法,關於這兩個介面的定義可以自行參考MSDN。在.NET 1.0中,.NET 類庫中很多集合都已經實現了迭代器模式,大家可以用反編譯工具Reflector來查看下mscorlib程式集下的System.Collections命名空間下的類,這裡給出ArrayList的定義代碼,具體實現代碼可以自行用反編譯工具查看,具體代碼如下所示:
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; private static readonly object[] emptyArray; 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關鍵字,實現迭代器模式就更簡單了,關於迭代器的更多內容可以參考我的這篇博文。
四、迭代器模式的適用情境
在下面的情況下可以考慮使用迭代器模式:
- 系統需要訪問一個彙總對象的內容而無需暴露它的內部表示。
- 系統需要支援對彙總對象的多種遍曆。
- 系統需要為不同的彙總結構提供一個統一的介面。
五、迭代器模式的優缺點
由於迭代器承擔了遍曆集合的職責,從而有以下的優點:
- 迭代器模式使得訪問一個彙總對象的內容而無需暴露它的內部表示,即迭代抽象。
- 迭代器模式為遍曆不同的集合結構提供了一個統一的介面,從而支援同樣的演算法在不同的集合結構上進行操作
迭代器模式存在的缺陷:
- 迭代器模式在遍曆的同時更改迭代器所在的集合結構會導致出現異常。所以使用foreach語句只能在對集合進行遍曆,不能在遍曆的同時更改集合中的元素。
六、總結
到這裡,本博文的內容就介紹結束了,迭代器模式就是抽象一個迭代器類來分離了集合對象的遍曆行為,這樣既可以做到不暴露集合的內部結構,又可讓外部代碼透明地訪問集合內部的資料。在一篇博文中將為大家介紹觀察者模式。
設計模式 - 迭代器模式