不能不說的C#特性-迭代器(上)及一些研究過程中的副產品
系列文章導航:
不能不說的C#特性-迭代器(下),yield以及流的延遲計算
走進Linq-Linq to SQL How do I(1)
走進Linq-Linq to SQL How do I(2)
走進Linq-Linq to SQL How do I(3)
走進Linq-Linq to SQL源代碼賞析 Table的獲取過程
走進Linq-Linq to SQL源代碼賞析之Provider的初始化
走進Linq-Linq to SQL源代碼賞析,通過Linq to SQL看Linq
提到迭代器我們不能不想到迭代器模式,那我就以迭代器模式作為開場白。
在我們的應用程序中常常有這樣一些數據結構:
它們是一個數據的集合,如果你知道它們內部的實現結構就可以去訪問它們,它們各自的內部存儲結構互不相同,各種集合有各自的應用場合.說到這里大家可能想出一大堆這樣的集合了:List,Hashtable,ArrayList等等。這些集合各自都有各自的個性,這就是它們存在的理由。但如果你想遍歷它你必須知道它內部的存儲細節,作為一個集合元素,把內部細節暴露出來肯定就不好了,這樣客戶程序就不夠穩定了,在你更換集合對象的時候,比如List不能滿足需求的時候,你換成Hashtable,因為以前的客戶程序過多的關注了List內部實現的細節,所以不能很好的移植。而迭代器模式就是為解決這個問題而生的:
提供一種一致的方式訪問集合對象中的元素,而無需暴露集合對象的內部表示。
比如現在有這樣一個需求,遍歷集合內的元素,然后輸出,但是并不限定集合是什么類型的集合,也就是未來集合可能發生改變。
思考:
集合會發生改變,這是變化點,集合改變了,遍歷方法也改變,我們要保證遍歷的方法穩定,那么就要屏蔽掉細節。找到了變化點那我們就將其隔離起來(一般使用interface作為隔離手段):假設所有的集合都繼承自ICollection接口,這個接口用來隔離具體集合的,將集合屏蔽在接口后面,作為遍歷我們肯定需要這樣一些方法:MoveNext,Current,既然ICollection負責數據存儲,職責又要單一,那么就新建立一個接口叫做Iterator吧,每種具體的集合都有自己相對應的Iterator實現:
下面是一個簡易的實現代碼:
/// 集合的接口
///
public interface ICollection
{
int Count { get; }
///
/// 獲取迭代器
///
/// 迭代器
Iterator GetIterator();
}
///
/// 迭代器接口
///
public interface Iterator
{
bool MoveNext();
object Current { get; }
}
public class List : ICollection
{
private const int MAX = 10;
private object[] items;
public List()
{
items = new object[MAX];
}
public object this[int i]
{
get { return items[i]; }
set { this.items[i] = value; }
}
#region ICollection Members
public int Count
{
get { return items.Length; }
}
public Iterator GetIterator()
{
return new ListIterator(this);
}
#endregion
}
public class ListIterator : Iterator
{
private int index = 0;
private ICollection list;
public ListIterator(ICollection list)
{
this.list = list;
index = 0;
}
#region Iterator Members
public bool MoveNext()
{
if (index + 1 > list.Count)
return false;
else
{
index++;
return true;
}
}
public object Current
{
get { return list[index]; }
}
#endregion
}
///
/// 測試
///
public class Program
{
static void Main()
{
ICollection list = new List();
Iterator iterator = list.GetIterator();
while (iterator.MoveNext())
{
object current = iterator.Current;
}
}
}