概述
在物件導向的軟體設計中,我們經常會遇到一類集合對象,這類集合對象的內部結構可能有著各種各樣的實現,但是歸結起來,無非有兩點是需要我們去關心的:一是集合內部的資料存放區結構,二是遍曆集合內部的資料。物件導向設計原則中有一條是類的單一職責原則,所以我們要儘可能的去分解這些職責,用不同的類去承擔不同的職責。Iterator模式就是分離了集合對象的遍曆行為,抽象出一個迭代器類來負責,這樣既可以做到不暴露集合的內部結構,又可讓外部代碼透明的訪問集合內部的資料。
意圖
提供一種方法順序訪問一個彙總對象中各個元素, 而又不需暴露該對象的內部表示。[GOF 《設計模式》]
結構圖
Iterator模式結構圖如下:
圖1 Iterator模式結構圖
生活中的例子
迭代器提供一種方法順序訪問一個集合對象中各個元素,而又不需要暴露該對象的內部表示。在早期的電視機中,一個撥盤用來改變頻道。當改變頻道時,需要手工轉動撥盤移過每一個頻道,而不論這個頻道是否有訊號。現在的電視機,使用[後一個]和[前一個]按鈕。當按下[後一個]按鈕時,將切換到下一個預置的頻道。想象一下在陌生的城市中的旅店中看電視。當改變頻道時,重要的不是幾頻道,而是節目內容。如果對一個頻道的節目不感興趣,那麼可以換下一個頻道,而不需要知道它是幾頻道。
圖2 使用選頻器做例子的Iterator模式對象圖
Iterator模式解說
在物件導向的軟體設計中,我們經常會遇到一類集合對象,這類集合對象的內部結構可能有著各種各樣的實現,但是歸結起來,無非有兩點是需要我們去關心的:一是集合內部的資料存放區結構,二是遍曆集合內部的資料。物件導向設計原則中有一條是類的單一職責原則,所以我們要儘可能的去分解這些職責,用不同的類去承擔不同的職責。Iterator模式就是分離了集合對象的遍曆行為,抽象出一個迭代器類來負責,這樣既可以做到不暴露集合的內部結構,又可讓外部代碼透明的訪問集合內部的資料。下面看一個簡單的示意性例子,類結構圖如下:
圖3 範例程式碼結構圖
首先有一個抽象的聚集,所謂的聚集就是就是資料的集合,可以迴圈去訪問它。它只有一個方法GetIterator()讓子類去實現,用來獲得一個迭代器對象。
/**//// <summary>
/// 抽象聚集
/// </summary>
public interface IList
{
IIterator GetIterator();
}
抽象的迭代器,它是用來訪問聚集的類,封裝了一些方法,用來把聚集中的資料按順序讀取出來。通常會有MoveNext()、CurrentItem()、Fisrt()、Next()等幾個方法讓子類去實現。
/**//// <summary>
/// 抽象迭代器
/// </summary>
public interface IIterator
{
bool MoveNext();
Object CurrentItem();
void First();
void Next();
}
具體的聚集,它實現了抽象聚集中的唯一的方法,同時在裡面儲存了一組資料,這裡我們加上Length屬性和GetElement()方法是為了便於訪問聚集中的資料。
/**//// <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];
}
}
具體迭代器,實現了抽象迭代器中的四個方法,在它的建構函式中需要接受一個具體聚集類型的參數,在這裡面我們可以根據實際的情況去編寫不同的迭代方式。
/**//// <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;
else
return false;
}
public Object CurrentItem()