C#面向對象設計模式縱橫談 第18講:Iterator 迭代器模式

>>>  技術話題—商業文明的嶄新時代  >>> 簡體     傳統

2006.7.12 李建忠

集合內部結構與外部訪問

image

 

動機(Motivation)

在軟件構建過程中,集合對象內部結構常常變化各異。但對于這些集合對象,我們希望在不暴露其內部結構的同時,可以讓外部客戶代碼透明地訪問其中包含的元素;同時這種“透明遍歷”也為“同一種算法在多種集合對象上進行操作”提供了可能。

使用面向對象技術將這種遍歷機制抽象為“迭代器對象”為“應對變化中的集合對象”提供了一種優雅的方式。

 

意圖(Intent)

提供一種方法順序訪問一個聚合對象中的各個元素,而又不暴露該對象的內部表示。

——《設計模式》GoF

 

例說Iterator應用

image

下面是迭代器所擁有的最小集合,Current是屬性,只能Get不能Set。還有兩個方法:MoveNext是往下一個元素走,如果訪問到最后一個元素之后沒有元素了,就返回False;Reset是復位,回到初始位置。

image

如果有一個容器實現了IEnumerable接口,它就可以支持我們的迭代操作了。

這種設計模式已經內化為C#語言的一種元素了,就是Foreach關鍵字。

我們定義的容器首先要實現IEnumerable接口,實現的GetEnumerator方法要返回一個IEnumerator的類型的集合。

image

image

Foreach的工作機制

image

遍歷代碼中訪問的全部是接口,而不用關心集合的內部結構。上面的代碼等同于下面的Foreach。

image

MyEnumerator集合類可以寫成private私有的,外部不可以訪問,只暴露接口給外部訪問。

 

結構(Structure)

image

Aggregate表示集合結構接口,對應例子中的IEnumerable,Iterator表示迭代器接口,對應IEnumerator。First()方法對應Reset(),Next()和IsDone對應MoveNext(),CurrentItem()對應Current屬性。Aggregate和Iterator的具體實現都只依賴于接口,而不依賴于具體實現,這樣就把兩者之間的耦合降低到最小。

 

Iterator模式的幾個要點

迭代抽象:訪問一個聚合對象的內容而無需暴露它的內部表示。

迭代多態:為遍歷不同的集合結構提供一個統一的接口,從而支持同樣的算法在不同的集合結構上進行操作。

例如假設我們有一個求和算法

image

它可以操作在多個支持迭代器的集合上,如果把這個算法寫成ArrayList的話,就會非常受限制。同時我們更可以用C#的Foreach語句來寫。

image

我們的算法應該是獨立的,寫的時候應該盡量操作接口,這樣我們寫好一個算法,就能應對N種集合的變化,使得同樣的算法能在不同的集合上操作。

迭代器的健壯性考慮:遍歷的同時更改迭代器所在的集合結構,會導致問題。

也就是說,我們在迭代的時候,應該只是讀取操作,不能更改容器的接口,例如遍歷的時候刪除一個元素,這樣是不可以的。容器的結構師絕對不能碰的,一旦結構更改,遍歷就會出問題。

image

下面這種情況對i進行更改,是不會影響原來的數組內容的,因為i是int類型,它只是一份拷貝。

image

image

我們一定要給用戶提供盡量純只讀的迭代。保證每個元素被且只被遍歷一次。

 

.NET 2.0中的Iterator

image

yield return關鍵字能夠支持迭代的簡化,動態生成迭代的類型。如果反編譯的話,能看見.NET內部能夠幫助我們構造一個之前我們寫的類,實現相應方法。雖然實現層面有所不同,但還是遵循了整體的迭代器定義的接口。能夠支持迭代的。

目前我們討論的迭代器游標都是往前走的,但我們也可以擴充方法,讓游標可以往回走,也可以設定游標的步長等等。

2010.10.17


MSDN 網絡廣播 李建忠 2013-08-22 08:51:09

[新一篇] C#面向對象設計模式縱橫談 第17講:Mediator 中介者模式

[舊一篇] C#面向對象設計模式縱橫談 第19講:Observer 觀察者模式
回頂部
寫評論


評論集


暫無評論。

稱謂:

内容:

驗證:


返回列表