- 迭代器模式
- 基於IEnumerable的實現
- 使用場景
- 迭代器模式的優缺點
迭代器模式
迭代器模式用於順序訪問集合對象的元素,而不需要知道集合對象的底層表示。Java和.Net等語言已經將迭代器作爲其內部語法元素,比如在C#中,集合對象只需要實現IEnumberable接口,然後就可以用foreach來遍歷了。
迭代器模式提示我們要從使用者的角度考慮如何設計接口,如何對外提供訪問內部對象的方式。即便我們組織的對象系統內部結構很複雜,但對於客戶程序而言最簡單的方式莫過於通過for /foreach循環依次遍歷,至於遍歷過程中的次序、分類篩選等則由目標類型自己封裝。
GOF對迭代器模式描述爲:
Provide a way to access the elements of an aggregate objectsequentially without exposing its underlying representation.
— Design Patterns : Elements of Reusable Object-Oriented Software
UML類圖:
代碼實現
//迭代器接口
public interface IIterator<T>
{
T Next();
bool HasNext();
}
//具體迭代器
public class ConcreteIterator<T> : IIterator<T>
{
private ConcreteAggretate<T> Aggretate; //成員變量,關聯關係
private int cursor = 0;
public ConcreteIterator(ConcreteAggretate<T> agg)
{
this.Aggretate = agg;
}
public bool HasNext()
{
return !(cursor >= Aggretate.Size);
}
public T Next()
{
if (HasNext())
{
return Aggretate.GetELement(cursor++);
}
else
{
return default(T);
}
}
}
//聚合接口
public interface IAggretate<T>
{
public void Add(T obj);
public void Remove(T obj);
public int Size { get; }
public T GetELement(int index);
public IIterator<T> GetIterator();
}
//具體聚合
public class ConcreteAggretate<T> : IAggretate<T>
{
private List<T> list = new List<T>(); //
public void Add(T obj)
{
list.Add(obj);
}
public void Remove(T obj)
{
list.Remove(obj);
}
public IIterator<T> GetIterator()
{
return new ConcreteIterator<T>(this); //在局部方法中new實例,屬依賴關係
}
public int Size
{
get
{
return list.Count;
}
}
public T GetELement(int index)
{
return list[index];
}
}
調用者代碼:
IAggretate<int> aggretate = new ConcreteAggretate<int>();
aggretate.Add(9);
aggretate.Add(8);
aggretate.Add(7);
IIterator<int> iterator = aggretate.GetIterator();
while (iterator.HasNext())
{
Console.WriteLine(iterator.Next());
}
基於IEnumerable的實現
以上便是經典的迭代器模式的實現,這種模式給聚合對象增加了一個創建其迭代器對象的方法,迭代器的抽象定義和具體迭代器類型都作爲一個額外的對象存在。
實際上C#已內置了對迭代器模式的支持,只需要實現IEnumerable接口即可,不再需要從0開始,少了很多代碼量:
public class ConcreteAggretate<T> : IEnumerable<T>
{
private List<T> list = new List<T>();
public void Add(T obj)
{
list.Add(obj);
}
public void Remove(T obj)
{
list.Remove(obj);
}
public IEnumerator<T> GetEnumerator()
{
foreach (var item in list)
{
yield return item;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
使用foreach遍歷IEnumerable接口
var aggretate = ConcreteAggretate<int>();
aggretate.Add(9);
aggretate.Add(8);
aggretate.Add(7);
foreach (var item in aggretate)
{
Console.WriteLine(item);
}
使用場景
- 對象內部結構比較複雜,爲了讓調用者可以輕鬆地訪問,同時不需要暴露其內部結構;
- 需要爲聚合對象提供多種遍歷方式;
- 爲遍歷不同的聚合結構提供一個統一的接口;
迭代器模式的優缺點
優點
- 迭代器支持以不同的方式遍歷一個聚合對象,而且在同一個聚合上可以添加多個具有不同遍歷方式的迭代器;
- 迭代器簡化了聚合類的遍歷;
- 迭代器模式可以方便地增加新的聚合類和迭代器類,無須修改原有代碼。
缺點
迭代器模式通過將存儲數據和遍歷數據的職責分離,爲封裝集合地複雜性、隔離變化提供了極大的遍歷,但這種方式也有其固有的缺點:每次
增加新的聚合類都需要對應增加新的迭代器類,類的個數成對增加,這在一定程度上增加了系統的複雜性。
參考書籍:
王翔著 《設計模式——基於C#的工程化實現及擴展》