听webcast的行为型模式篇-迭代器模式(Iterator Pattern) 记录
dotnet或java里面這種設(shè)計模式已經(jīng)集成在foreach里面了,同時想到我們應(yīng)該用面向接口編程,類太脆弱易變,只能is a,而接口是穩(wěn)定的是became,as.下面是聽webcast講師的記錄.
??????? 概述
??????? 在面向?qū)ο蟮能浖O(shè)計中,我們經(jīng)常會遇到一類集合對象,這類集合對象的內(nèi)部結(jié)構(gòu)可能有著各種各樣的實現(xiàn),但是歸結(jié)起來,無非有兩點是需要我們?nèi)リP(guān)心的:一是集合內(nèi)部的數(shù)據(jù)存儲結(jié)構(gòu),二是遍歷集合內(nèi)部的數(shù)據(jù)。面向?qū)ο笤O(shè)計原則中有一條是類的單一職責(zé)原則,所以我們要盡可能的去分解這些職責(zé),用不同的類去承擔(dān)不同的職責(zé)。Iterator模式就是分離了集合對象的遍歷行為,抽象出一個迭代器類來負(fù)責(zé),這樣既可以做到不暴露集合的內(nèi)部結(jié)構(gòu),又可讓外部代碼透明的訪問集合內(nèi)部的數(shù)據(jù)。
????意圖
??????? 提供一種方法順序訪問一個聚合對象中各個元素, 而又不需暴露該對象的內(nèi)部表示。[GOF 《設(shè)計模式》]
????結(jié)構(gòu)圖
??????? Iterator模式結(jié)構(gòu)圖如下:
圖1 Iterator模式結(jié)構(gòu)圖
????生活中的例子
??????? 迭代器提供一種方法順序訪問一個集合對象中各個元素,而又不需要暴露該對象的內(nèi)部表示。在早期的電視機中,一個撥盤用來改變頻道。當(dāng)改變頻道時,需要手工轉(zhuǎn)動撥盤移過每一個頻道,而不論這個頻道是否有信號?,F(xiàn)在的電視機,使用[后一個]和[前一個]按鈕。當(dāng)按下[后一個]按鈕時,將切換到下一個預(yù)置的頻道。想象一下在陌生的城市中的旅店中看電視。當(dāng)改變頻道時,重要的不是幾頻道,而是節(jié)目內(nèi)容。如果對一個頻道的節(jié)目不感興趣,那么可以換下一個頻道,而不需要知道它是幾頻道。
圖2 使用選頻器做例子的Iterator模式對象圖
????Iterator模式解說
????在面向?qū)ο蟮能浖O(shè)計中,我們經(jīng)常會遇到一類集合對象,這類集合對象的內(nèi)部結(jié)構(gòu)可能有著各種各樣的實現(xiàn),但是歸結(jié)起來,無非有兩點是需要我們?nèi)リP(guān)心的:一是集合內(nèi)部的數(shù)據(jù)存儲結(jié)構(gòu),二是遍歷集合內(nèi)部的數(shù)據(jù)。面向?qū)ο笤O(shè)計原則中有一條是類的單一職責(zé)原則,所以我們要盡可能的去分解這些職責(zé),用不同的類去承擔(dān)不同的職責(zé)。Iterator模式就是分離了集合對象的遍歷行為,抽象出一個迭代器類來負(fù)責(zé),這樣既可以做到不暴露集合的內(nèi)部結(jié)構(gòu),又可讓外部代碼透明的訪問集合內(nèi)部的數(shù)據(jù)。下面看一個簡單的示意性例子,類結(jié)構(gòu)圖如下:
圖3 示例代碼結(jié)構(gòu)圖
??????? 首先有一個抽象的聚集,所謂的聚集就是就是數(shù)據(jù)的集合,可以循環(huán)去訪問它。它只有一個方法GetIterator()讓子類去實現(xiàn),用來獲得一個迭代器對象。
??????? 抽象的迭代器,它是用來訪問聚集的類,封裝了一些方法,用來把聚集中的數(shù)據(jù)按順序讀取出來。通常會有MoveNext()、CurrentItem()、Fisrt()、Next()等幾個方法讓子類去實現(xiàn)。
/// <summary>/// 抽象迭代器/// </summary> public interface IIterator{bool MoveNext();Object CurrentItem();void First();void Next();}??????? 具體的聚集,它實現(xiàn)了抽象聚集中的唯一的方法,同時在里面保存了一組數(shù)據(jù),這里我們加上Length屬性和GetElement()方法是為了便于訪問聚集中的數(shù)據(jù)。
/// <summary>/// 具體聚集/// </summary>public class ConcreteList : IList{int[] list;public ConcreteList(){list = new int[] { 1,2,3,4,5};}public IIterator GetIterator(){return new ConcreteIterator(this);}public int Length{get { return list.Length; }}public int GetElement(int index){return list[index];}}??????? 具體迭代器,實現(xiàn)了抽象迭代器中的四個方法,在它的構(gòu)造函數(shù)中需要接受一個具體聚集類型的參數(shù),在這里面我們可以根據(jù)實際的情況去編寫不同的迭代方式。
/// <summary>/// 具體迭代器/// </summary> public class ConcreteIterator : IIterator{private ConcreteList list;private int index;public ConcreteIterator(ConcreteList list){this.list = list;index = 0;}public bool MoveNext(){if (index < list.Length)return true;elsereturn false;}public Object CurrentItem(){return list.GetElement(index) ;}public void First(){index = 0;}public void Next(){if (index < list.Length){index++;}}}??????? 簡單的客戶端程序調(diào)用:
/// <summary>/// 客戶端程序/// </summary> class Program{static void Main(string[] args){IIterator iterator;IList list = new ConcreteList();iterator = list.GetIterator();while (iterator.MoveNext()){int i = (int)iterator.CurrentItem();Console.WriteLine(i.ToString());iterator.Next();}Console.Read();}} ??????? 一個簡單的迭代器示例就結(jié)束了,這里我們并沒有利用任何的.NET特性,在C#中,實現(xiàn)Iterator模式已經(jīng)不需要這么麻煩了,已經(jīng)C#語言本身就有一些特定的實現(xiàn),下面會說到。
????.NET中的Iterator模式
????在.NET下實現(xiàn)Iterator模式,對于聚集接口和迭代器接口已經(jīng)存在了,其中IEnumerator扮演的就是迭代器的角色,它的實現(xiàn)如下:
public interface IEumerator{object Current{get;}bool MoveNext();void Reset();} ??????? 屬性Current返回當(dāng)前集合中的元素,Reset()方法恢復(fù)初始化指向的位置,MoveNext()方法返回值true表示迭代器成功前進(jìn)到集合中的下一個元素,返回值false表示已經(jīng)位于集合的末尾。能夠提供元素遍歷的集合對象,在.Net中都實現(xiàn)了IEnumerator接口。
??????? IEnumerable則扮演的就是抽象聚集的角色,只有一個GetEnumerator()方法,如果集合對象需要具備跌代遍歷的功能,就必須實現(xiàn)該接口。
??????? 下面看一個在.NET1.1下的迭代器例子,Person類是一個可枚舉的類。PersonsEnumerator類是一個枚舉器類。這個例子來自于http://www.theserverside.net/,被我簡單的改造了一下。
public class Persons : IEnumerable{public string[] m_Names;public Persons(params string[] Names){m_Names = new string[Names.Length];Names.CopyTo(m_Names,0);}private string this[int index]{get{return m_Names[index];}set{m_Names[index] = value;}}public IEnumerator GetEnumerator(){return new PersonsEnumerator(this);}}public class PersonsEnumerator : IEnumerator{private int index = -1;private Persons P;public PersonsEnumerator(Persons P){this.P = P;}public bool MoveNext(){index++;return index < P.m_Names.Length;}public void Reset(){index = -1;}public object Current{get{return P.m_Names[index];}}}??????? 來看客戶端代碼的調(diào)用:
class Program{static void Main(string[] args){Persons arrPersons = new Persons("Michel","Christine","Mathieu","Julien");foreach (string s in arrPersons){Console.WriteLine(s);}Console.ReadLine();}} ??????? 程序?qū)⑤敵?#xff1a;
??????? Michel
??????? Christine
??????? Mathieu
??????? Julien
??????? 現(xiàn)在我們分析編譯器在執(zhí)行foreach語句時到底做了什么,它執(zhí)行的代碼大致如下:
class Program{static void Main(string[] args){Persons arrPersons = new Persons("Michel","Christine","Mathieu","Julien");IEnumerator e = arrPersons.GetEnumerator();while (e.MoveNext()){Console.WriteLine((string)e.Current);}Console.ReadLine();}}??????? 可以看到這段代碼跟我們最前面提到的示例代碼非常的相似。同時在這個例子中,我們把大部分的精力都花在了實現(xiàn)迭代器和可迭代的類上面,在.NET2.0下面,由于有了yield return關(guān)鍵字,實現(xiàn)起來將更加的簡單優(yōu)雅。下面我們把剛才的例子在2.0下重新實現(xiàn)一遍:
public class Persons : IEnumerable{string[] m_Names;public Persons(params string[] Names){m_Names = new string[Names.Length];Names.CopyTo(m_Names,0);}public IEnumerator GetEnumerator(){foreach (string s in m_Names){yield return s;}}}class Program{static void Main(string[] args){Persons arrPersons = new Persons("Michel","Christine","Mathieu","Julien");foreach (string s in arrPersons){Console.WriteLine(s);}Console.ReadLine();}} ??????? 程序?qū)⑤敵?#xff1a;
??????? Michel
??????? Christine
??????? Mathieu
??????? Julien
??????? 實現(xiàn)相同的功能,由于有了yield return關(guān)鍵字,變得非常的簡單。好了,關(guān)于.NET中的Iterator模式就說這么多了,更詳細(xì)的內(nèi)容大家可以參考相關(guān)的資料。
????效果及實現(xiàn)要點
??????? 1 .迭代抽象:訪問一個聚合對象的內(nèi)容而無需暴露它的內(nèi)部表示。
??????? 2.迭代多態(tài):為遍歷不同的集合結(jié)構(gòu)提供一個統(tǒng)一的接口,從而支持同樣的算法在不同的集合結(jié)構(gòu)上進(jìn)行操作。
??????? 3.迭代器的健壯性考慮:遍歷的同時更改迭代器所在的集合結(jié)構(gòu),會導(dǎo)致問題。
????適用性
??????? 1.訪問一個聚合對象的內(nèi)容而無需暴露它的內(nèi)部表示。
??????? 2.支持對聚合對象的多種遍歷。
??????? 3.為遍歷不同的聚合結(jié)構(gòu)提供一個統(tǒng)一的接口(即, 支持多態(tài)迭代)。
??? 總結(jié)
??????? Iterator模式就是分離了集合對象的遍歷行為,抽象出一個迭代器類來負(fù)責(zé),這樣既可以做到不暴露集合的內(nèi)部結(jié)構(gòu),又可讓外部代碼透明的訪問集合內(nèi)部的數(shù)據(jù)。
總結(jié)
以上是生活随笔為你收集整理的听webcast的行为型模式篇-迭代器模式(Iterator Pattern) 记录的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 自己动手制作笔记本SP2系统安装光盘
- 下一篇: .NET 2.0 CER学习笔记