設計模式(17) 迭代器模式

  • 迭代器模式
  • 基於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#的工程化實現及擴展》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章