概述
在面向對象的軟件設計中,咱們常常會遇到一類集合對象,這類集合對象的內部結構可能有着各類各樣的實現,可是歸結起來,無非有兩點是須要咱們去關心的:一是集合內部的數據存儲結構,二是遍歷集合內部的數據。面向對象設計原則中有一條是類的單一職責原則,因此咱們要儘量的去分解這些職責,用不一樣的類去承擔不一樣的職責。Iterator模式就是分離了集合對象的遍歷行爲,抽象出一個迭代器類來負責,這樣既能夠作到不暴露集合的內部結構,又可以讓外部代碼透明的訪問集合內部的數據。
意圖
提供一種方法順序訪問一個聚合對象中各個元素, 而又不需暴露該對象的內部表示。[GOF 《設計模式》]
結構圖
Iterator
模式結構圖以下:
圖1 Iterator模式結構圖
生活中的例子
迭代器提供一種方法順序訪問一個集合對象中各個元素,而又不須要暴露該對象的內部表示。在早期的電視機中,一個撥盤用來改變頻道。當改變頻道時,須要手工轉動撥盤移過每個頻道,而不論這個頻道是否有信號。如今的電視機,使用[後一個]和[前一個]按鈕。當按下[後一個]按鈕時,將切換到下一個預置的頻道。想象一下在陌生的城市中的旅店中看電視。當改變頻道時,重要的不是幾頻道,而是節目內容。若是對一個頻道的節目不感興趣,那麼能夠換下一個頻道,而不須要知道它是幾頻道。
圖2 使用選頻器作例子的Iterator模式對象圖
Iterator
模式解說
在面向對象的軟件設計中,咱們常常會遇到一類集合對象,這類集合對象的內部結構可能有着各類各樣的實現,可是歸結起來,無非有兩點是須要咱們去關心的:一是集合內部的數據存儲結構,二是遍歷集合內部的數據。面向對象設計原則中有一條是類的單一職責原則,因此咱們要儘量的去分解這些職責,用不一樣的類去承擔不一樣的職責。Iterator模式就是分離了集合對象的遍歷行爲,抽象出一個迭代器類來負責,這樣既能夠作到不暴露集合的內部結構,又可以讓外部代碼透明的訪問集合內部的數據。下面看一個簡單的示意性例子,類結構圖以下:
圖3 示例代碼結構圖
首先有一個抽象的彙集,所謂的彙集就是就是數據的集合,能夠循環去訪問它。它只有一個方法GetIterator()讓子類去實現,用來得到一個迭代器對象。
/**/
/// <summary>
![](http://static.javashuo.com/static/loading.gif)
/// 抽象彙集
![](http://static.javashuo.com/static/loading.gif)
/// </summary>
public
interface
IList
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
{
IIterator GetIterator();
}
抽象的迭代器,它是用來訪問彙集的類,封裝了一些方法,用來把彙集中的數據按順序讀取出來。一般會有
MoveNext()、
CurrentItem()、
Fisrt()、
Next()等幾個方法讓子類去實現。
/**/
/// <summary>
![](http://static.javashuo.com/static/loading.gif)
/// 抽象迭代器
![](http://static.javashuo.com/static/loading.gif)
/// </summary>
public
interface
IIterator
![](http://static.javashuo.com/static/loading.gif)
{
bool MoveNext();
![](http://static.javashuo.com/static/loading.gif)
Object CurrentItem();
![](http://static.javashuo.com/static/loading.gif)
void First();
![](http://static.javashuo.com/static/loading.gif)
void Next();
}
具體的彙集,它實現了抽象彙集中的惟一的方法,同時在裏面保存了一組數據,這裏咱們加上
Length屬性和
GetElement()方法是爲了便於訪問彙集中的數據。
/**/
/// <summary>
![](http://static.javashuo.com/static/loading.gif)
/// 具體彙集
![](http://static.javashuo.com/static/loading.gif)
/// </summary>
public
class
ConcreteList : IList
![](http://static.javashuo.com/static/loading.gif)
{
int[] list;
![](http://static.javashuo.com/static/loading.gif)
public ConcreteList()
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
{
![](http://static.javashuo.com/static/loading.gif)
list = new int[]
{ 1,2,3,4,5};
}
![](http://static.javashuo.com/static/loading.gif)
public IIterator GetIterator()
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
{
return new ConcreteIterator(this);
}
![](http://static.javashuo.com/static/loading.gif)
public int Length
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
{
![](http://static.javashuo.com/static/loading.gif)
get
{ return list.Length; }
}
![](http://static.javashuo.com/static/loading.gif)
public int GetElement(int index)
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
{
return list[index];
}
}
具體迭代器,實現了抽象迭代器中的四個方法,在它的構造函數中須要接受一個具體彙集類型的參數,在這裏面咱們能夠根據實際的狀況去編寫不一樣的迭代方式。
/**/
/// <summary>
![](http://static.javashuo.com/static/loading.gif)
/// 具體迭代器
![](http://static.javashuo.com/static/loading.gif)
/// </summary>
public
class
ConcreteIterator : IIterator
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
{
private ConcreteList list;
![](http://static.javashuo.com/static/loading.gif)
private int index;
![](http://static.javashuo.com/static/loading.gif)
public ConcreteIterator(ConcreteList list)
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
{
this.list = list;
![](http://static.javashuo.com/static/loading.gif)
index = 0;
}
![](http://static.javashuo.com/static/loading.gif)
public bool MoveNext()
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
{
if (index < list.Length)
![](http://static.javashuo.com/static/loading.gif)
return true;
![](http://static.javashuo.com/static/loading.gif)
else
![](http://static.javashuo.com/static/loading.gif)
return false;
}
![](http://static.javashuo.com/static/loading.gif)
public Object CurrentItem()
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
{
return list.GetElement(index) ;
}
![](http://static.javashuo.com/static/loading.gif)
public void First()
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
{
index = 0;
}
![](http://static.javashuo.com/static/loading.gif)
public void Next()
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
{
if (index < list.Length)
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
{
index++;
}
}
}
簡單的客戶端程序調用:
/**/
/// <summary>
![](http://static.javashuo.com/static/loading.gif)
/// 客戶端程序
![](http://static.javashuo.com/static/loading.gif)
/// </summary>
class
Program
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
{
static void Main(string[] args)
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
{
IIterator iterator;
![](http://static.javashuo.com/static/loading.gif)
IList list = new ConcreteList();
![](http://static.javashuo.com/static/loading.gif)
iterator = list.GetIterator();
![](http://static.javashuo.com/static/loading.gif)
while (iterator.MoveNext())
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
{
int i = (int)iterator.CurrentItem();
Console.WriteLine(i.ToString());
![](http://static.javashuo.com/static/loading.gif)
iterator.Next();
}
![](http://static.javashuo.com/static/loading.gif)
Console.Read();
![](http://static.javashuo.com/static/loading.gif)
}
![](http://static.javashuo.com/static/loading.gif)
}
一個簡單的迭代器示例就結束了,這裏咱們並無利用任何的
.NET特性,在
C#中,實現
Iterator模式已經不須要這麼麻煩了,已經
C#語言自己就有一些特定的實現,下面會說到。
.NET
中的Iterator模式
在.NET下實現Iterator模式,對於彙集接口和迭代器接口已經存在了,其中IEnumerator扮演的就是迭代器的角色,它的實現以下:
public
interface
IEumerator
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
{
object Current
![](http://static.javashuo.com/static/loading.gif)
{
get;
}
![](http://static.javashuo.com/static/loading.gif)
bool MoveNext();
![](http://static.javashuo.com/static/loading.gif)
void Reset();
![](http://static.javashuo.com/static/loading.gif)
}
屬性
Current返回當前集合中的元素,
Reset()方法恢復初始化指向的位置,
MoveNext()方法返回值
true表示迭代器成功前進到集合中的下一個元素,返回值
false表示已經位於集合的末尾。可以提供元素遍歷的集合對象,在
.Net中都實現了
IEnumerator接口。
IEnumerable
則扮演的就是抽象彙集的角色,只有一個GetEnumerator()方法,若是集合對象須要具有跌代遍歷的功能,就必須實現該接口。
public
interface
IEnumerable
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
{
IEumerator GetEnumerator();
}
public
class
Persons : IEnumerable
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
{
public string[] m_Names;
![](http://static.javashuo.com/static/loading.gif)
public Persons(params string[] Names)
![](http://static.javashuo.com/static/loading.gif)
{
m_Names = new string[Names.Length];
![](http://static.javashuo.com/static/loading.gif)
Names.CopyTo(m_Names,0);
}
![](http://static.javashuo.com/static/loading.gif)
private string this[int index]
![](http://static.javashuo.com/static/loading.gif)
{
get
![](http://static.javashuo.com/static/loading.gif)
{
return m_Names[index];
}
![](http://static.javashuo.com/static/loading.gif)
set
![](http://static.javashuo.com/static/loading.gif)
{
m_Names[index] = value;
}
}
![](http://static.javashuo.com/static/loading.gif)
public IEnumerator GetEnumerator()
![](http://static.javashuo.com/static/loading.gif)
{
return new PersonsEnumerator(this);
}
}
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
public
class
PersonsEnumerator : IEnumerator
![](http://static.javashuo.com/static/loading.gif)
{
private int index = -1;
![](http://static.javashuo.com/static/loading.gif)
private Persons P;
![](http://static.javashuo.com/static/loading.gif)
public PersonsEnumerator(Persons P)
![](http://static.javashuo.com/static/loading.gif)
{
this.P = P;
}
![](http://static.javashuo.com/static/loading.gif)
public bool MoveNext()
![](http://static.javashuo.com/static/loading.gif)
{
index++;
![](http://static.javashuo.com/static/loading.gif)
return index < P.m_Names.Length;
}
![](http://static.javashuo.com/static/loading.gif)
public void Reset()
![](http://static.javashuo.com/static/loading.gif)
{
index = -1;
}
![](http://static.javashuo.com/static/loading.gif)
public object Current
![](http://static.javashuo.com/static/loading.gif)
{
get
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
{
return P.m_Names[index];
}
}
}
來看客戶端代碼的調用:
class
Program
![](http://static.javashuo.com/static/loading.gif)
{
static void Main(string[] args)
![](http://static.javashuo.com/static/loading.gif)
{
Persons arrPersons = new Persons("Michel","Christine","Mathieu","Julien");
![](http://static.javashuo.com/static/loading.gif)
foreach (string s in arrPersons)
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
{
Console.WriteLine(s);
}
![](http://static.javashuo.com/static/loading.gif)
Console.ReadLine();
}
}
程序將輸出:
Michel
![](http://static.javashuo.com/static/loading.gif)
Christine
![](http://static.javashuo.com/static/loading.gif)
Mathieu
![](http://static.javashuo.com/static/loading.gif)
Julien
如今咱們分析編譯器在執行
foreach語句時到底作了什麼,它執行的代碼大體以下:
class
Program
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
{
static void Main(string[] args)
![](http://static.javashuo.com/static/loading.gif)
{
Persons arrPersons = new Persons("Michel","Christine","Mathieu","Julien");
![](http://static.javashuo.com/static/loading.gif)
IEnumerator e = arrPersons.GetEnumerator();
![](http://static.javashuo.com/static/loading.gif)
while (e.MoveNext())
![](http://static.javashuo.com/static/loading.gif)
{
Console.WriteLine((string)e.Current);
![](http://static.javashuo.com/static/loading.gif)
}
![](http://static.javashuo.com/static/loading.gif)
Console.ReadLine();
}
}
能夠看到這段代碼跟咱們最前面提到的示例代碼很是的類似。同時在這個例子中,咱們把大部分的精力都花在了實現迭代器和可迭代的類上面,在
.NET2.0下面,因爲有了
yield return關鍵字,實現起來將更加的簡單優雅。下面咱們把剛纔的例子在
2.0下從新實現一遍:
public
class
Persons : IEnumerable
![](http://static.javashuo.com/static/loading.gif)
{
string[] m_Names;
![](http://static.javashuo.com/static/loading.gif)
public Persons(params string[] Names)
![](http://static.javashuo.com/static/loading.gif)
{
m_Names = new string[Names.Length];
![](http://static.javashuo.com/static/loading.gif)
Names.CopyTo(m_Names,0);
}
![](http://static.javashuo.com/static/loading.gif)
public IEnumerator GetEnumerator()
![](http://static.javashuo.com/static/loading.gif)
{
foreach (string s in m_Names)
![](http://static.javashuo.com/static/loading.gif)
{
yield return s;
}
}
}
![](http://static.javashuo.com/static/loading.gif)
class
Program
![](http://static.javashuo.com/static/loading.gif)
{
static void Main(string[] args)
![](http://static.javashuo.com/static/loading.gif)
{
Persons arrPersons = new Persons("Michel","Christine","Mathieu","Julien");
![](http://static.javashuo.com/static/loading.gif)
foreach (string s in arrPersons)
![](http://static.javashuo.com/static/loading.gif)
{
Console.WriteLine(s);
}
![](http://static.javashuo.com/static/loading.gif)
Console.ReadLine();
}
}
程序將輸出:
Michel
![](http://static.javashuo.com/static/loading.gif)
Christine
![](http://static.javashuo.com/static/loading.gif)
Mathieu
![](http://static.javashuo.com/static/loading.gif)
Julien
實現相同的功能,因爲有了
yield return關鍵字,變得很是的簡單。好了,關於
.NET中的
Iterator模式就說這麼多了,更詳細的內容你們能夠參考相關的資料。
效果及實現要點
1
.迭代抽象:訪問一個聚合對象的內容而無需暴露它的內部表示。
2
.迭代多態:爲遍歷不一樣的集合結構提供一個統一的接口,從而支持一樣的算法在不一樣的集合結構上進行操做。
3
.迭代器的健壯性考慮:遍歷的同時更改迭代器所在的集合結構,會致使問題。
適用性
1
.訪問一個聚合對象的內容而無需暴露它的內部表示。
2
.支持對聚合對象的多種遍歷。
3
.爲遍歷不一樣的聚合結構提供一個統一的接口(即, 支持多態迭代)。
總結
Iterator
模式就是分離了集合對象的遍歷行爲,抽象出一個迭代器類來負責,這樣既能夠作到不暴露集合的內部結構,又可以讓外部代碼透明的訪問集合內部的數據。
參考資料
Erich Gamma
等,《設計模式:可複用面向對象軟件的基礎》,機械工業出版社
Robert C.Martin
,《敏捷軟件開發:原則、模式與實踐》,清華大學出版社
閻宏,《Java與模式》,電子工業出版社
Alan Shalloway James R. Trott
,《Design Patterns Explained》,中國電力出版社
MSDN WebCast
《C#面向對象設計模式縱橫談(18):Iterator 迭代器模式(行爲型模式)》