Gof定義
提供一種方法順序訪問一個聚合對象中的各個元素, 而又不暴露該對象的內部表示。
動機
在軟件構建過程中,集合對象內部結構常常變化各異。但對於這些集合對象,我們希望在不暴露其內部結構的同時,可以讓外部客戶代碼透明地訪問其中包含的元素;同時這種“透明遍歷”也爲“同一種算法在多種集合對象上進行操作”提供了可能。使用面向對象技術將這種遍歷機制抽象爲“迭代器對象”爲“應對變化中的集合對象”提供了一種優雅的方式。
迭代器模式結構圖:
Aggregate:集合結構接口
Iterator:迭代器接口
Concreteaggregate:集合結構的具體類,繼承Aggregate接口
ConcreteIteator:具體的迭代器類
代碼實現:
/// <summary> /// 集合結構接口 /// </summary> public interface Aggregate { Iterator CreateIterator(); } /// <summary> /// 迭代器接口 /// </summary> public interface Iterator { object First(); object Next(); bool IsDone(); object CurrentItem(); } /// <summary> /// 集合結構的具體類 /// </summary> class ConcreteAggregate : Aggregate { private List<object> items = new List<object>(); public Iterator CreateIterator() { return new ConcreteIterator(this); } public int Count { get { return items.Count; } } public object this[int index] { get { return items[index]; } set { items.Insert(index, value); } } } /// <summary> /// 具體的迭代器類 /// </summary> class ConcreteIterator : Iterator { private ConcreteAggregate _aggregate; private int _current = 0; public ConcreteIterator(ConcreteAggregate aggregate) { this._aggregate = aggregate; } public object First() { return _aggregate[0]; } public object Next() { object r = null; _current++; if (_current < _aggregate.Count) { r = _aggregate[_current]; } return r; } public bool IsDone() { return _current >= _aggregate.Count ? true : false; } public object CurrentItem() { return _aggregate[_current]; } } /// <summary> /// 客戶端調用 /// </summary> class Program { static void Main(string[] args) { ConcreteAggregate ca = new ConcreteAggregate(); ca[0] = "AspNet3.5 揭祕"; ca[0] = "重構:改善既有代碼的設計"; ca[2] = "設計模式"; ca[3] = "人月神話"; ca[4] = "代碼大全2"; Iterator i = new ConcreteIterator(ca); while (!i.IsDone()) { Console.WriteLine("要讀的書:" + i.CurrentItem()); i.Next(); } } }
上面的代碼是根據結構圖實現的基礎代碼,在設計的運用中可以使用Net框架給我們提供的相關接口IEnumerable和IEnumerator,這兩個接口在Net中的實現代碼如下:
public interface IEnumerable { IEmumerator GetEnumerator(); } public interface IEmumerator { Object Current { get; } bool MoveNext(); void Reset(); }
在Net中List實現了IEnumerable接口,下面的代碼將List作爲數據的容器來實現遍歷:
class Program { static void Main(string[] args) { List<string> list = new List<string> { "AspNet3.5 揭祕","重構:改善既有代碼的設計","設計模式", "人月神話","代碼大全2" }; IEnumerator i = list.GetEnumerator(); while (i.MoveNext()) { Console.WriteLine("要讀的書:" + i.Current); } } }
上面的代碼中試調用List的GetEnumerator方法返回IEmumerator類型的集合,然後取遍歷,這樣仍然顯得比較麻煩,其實在Net中foreach已經實現了這樣的功能,代碼如下:
class Program { static void Main(string[] args) { List<string> list = new List<string> { "AspNet3.5 揭祕","重構:改善既有代碼的設計","設計模式", "人月神話","代碼大全2" }; foreach (string s in list) { Console.WriteLine("要讀的書:" + s); } } }
可以看出foreach其實就是實現了下面這段代碼
IEnumerator i = list.GetEnumerator(); while (i.MoveNext()) { Console.WriteLine("要讀的書:" + i.Current); }
Iterator模式的幾個要點
- 迭代抽象:訪問一個聚合對象的內容而無需暴露它的內部表示。
迭代多態:爲遍歷不同的集合結構提供一個統一的接口,從而支持同樣的算法在不同的集合結構上進行操作。
迭代器的健壯性考慮:遍歷的同時更改迭代器所在的集合結構,會導致問題。