歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

C#設計模式-迭代器模式

一、 迭代器(Iterator)模式

迭代器是針對集合對象而生的,對於集合對象而言,必然涉及到集合元素的添加刪除操作,同時也肯定支持遍歷集合元素的操作,我們此時可以把遍歷操作也放在集合對象中,但這樣的話,集合對象就承擔太多的責任了,面向對象設計原則中有一條是單一職責原則,所以我們要盡可能地分離這些職責,用不同的類去承擔不同的職責。迭代器模式就是用迭代器類來承擔遍歷集合元素的職責。

迭代器模式提供了一種方法順序訪問一個聚合對象(理解為集合對象)中各個元素,而又無需暴露該對象的內部表示,這樣既可以做到不暴露集合的內部結構,又可讓外部代碼透明地訪問集合內部的數據。

二、 迭代器模式的結構

既然,迭代器模式承擔了遍歷集合對象的職責,則該模式自然存在2個類,一個是聚合類,一個是迭代器類。在面向對象涉及原則中還有一條是針對接口編程,所以,在迭代器模式中,抽象了2個接口,一個是聚合接口,另一個是迭代器接口,這樣迭代器模式中就四個角色了,具體的類圖如下所示:

從上圖可以看出,迭代器模式由以下角色組成:

  • 迭代器角色(Iterator):迭代器角色負責定義訪問和遍歷元素的接口
  • 具體迭代器角色(Concrete Iteraror):具體迭代器角色實現了迭代器接口,並需要記錄遍歷中的當前位置。
  • 聚合角色(Aggregate):聚合角色負責定義獲得迭代器角色的接口
  • 具體聚合角色(Concrete Aggregate):具體聚合角色實現聚合角色接口。

三、 迭代器模式的實現

// 抽象聚合類

using System;

public interface IListCollection
{
    Iterator GetIterator();
}

// 迭代器抽象類
public interface Iterator
{
    bool MoveNext();
    Object GetCurrent();
    void Next();
    void Reset();
}

// 具體聚合類
public class ConcreteList : IListCollection
{
    readonly int[] _collection;
    public ConcreteList()
    {
        _collection = new int[] { 2, 4, 6, 8 };
    }

    public Iterator GetIterator()
    {
        return new ConcreteIterator(this);
    }

    public int Length
    {
        get { return _collection.Length; }
    }

    public int GetElement(int index)
    {
        return _collection[index];
    }
}

// 具體迭代器類
public class ConcreteIterator : Iterator
{
    // 迭代器要集合對象進行遍歷操作,自然就需要引用集合對象
    private readonly ConcreteList _list;
    private int _index;

    public ConcreteIterator(ConcreteList list)
    {
        _list = list;
        _index = 0;
    }


    public bool MoveNext()
    {
        if (_index < _list.Length)
        {
            return true;
        }
        return false;
    }

    public Object GetCurrent()
    {
        return _list.GetElement(_index);
    }

    public void Reset()
    {
        _index = 0;
    }

    public void Next()
    {
        if (_index < _list.Length)
        {
            _index++;
        }

    }
}

// 客戶端
class Program
{
    static void Main(string[] args)
    {
        IListCollection list = new ConcreteList();
        Iterator iterator = list.GetIterator();

        while (iterator.MoveNext())
        {
            var i = (int)iterator.GetCurrent();
            Console.WriteLine(i.ToString());
            iterator.Next();
        }

        Console.Read();
    }
}

自然,上面代碼的運行結果也是對集合每個元素的輸出,具體運行結果如下所示:

2
4
6
8

四、 .NET中迭代器模式的應用

在.NET下,迭代器模式中的聚集接口和迭代器接口都已經存在了,其中IEnumerator接口扮演的就是迭代器角色,IEnumberable接口則扮演的就是抽象聚集的角色,只有一個GetEnumerator()方法,關於這兩個接口的定義可以自行參考MSDN。在.NET 1.0中,.NET 類庫中很多集合都已經實現了迭代器模式,大家可以用反編譯工具Reflector來查看下mscorlib程序集下的System.Collections命名空間下的類,這裡給出ArrayList的定義代碼,具體實現代碼可以自行用反編譯工具查看,具體代碼如下所示:

using System;
using System.Collections;
using System.Collections.Generic;

public class ArrayList : IList, ICollection, IEnumerable, ICloneable
{
    // Fields
    private const int DefaultCapacity = 4;
    private object[] _items;
    private int _size;
    [NonSerialized]
    private object _syncRoot;
    private int _version;

    public ArrayList(object[] items, int size, object syncRoot, int version)
    {
        _items = items;
        _size = size;
        _syncRoot = syncRoot;
        _version = version;
    }

    public virtual IEnumerator GetEnumerator();
    public virtual IEnumerator<> GetEnumerator(int index, int count);

    // Properties
    public virtual int Capacity { get; set; }
    public virtual int Count { get; }
    ..............// 更多代碼請自行用反編譯工具Reflector查看
}

通過查看源碼你可以發現,ArrayList中迭代器的實現與我們前面給出的示例代碼非常相似。然而,在.NET 2.0中,由於有了yield return關鍵字,實現迭代器模式就更簡單了。

五、 迭代器模式的適用場景

在下面的情況下可以考慮使用迭代器模式:

  1. 系統需要訪問一個聚合對象的內容而無需暴露它的內部表示。
  2. 系統需要支持對聚合對象的多種遍歷。
  3. 系統需要為不同的聚合結構提供一個統一的接口。

六、 迭代器模式的優缺點

優點:

  1. 迭代器模式使得訪問一個聚合對象的內容而無需暴露它的內部表示,即迭代抽象。
  2. 迭代器模式為遍歷不同的集合結構提供了一個統一的接口,從而支持同樣的算法在不同的集合結構上進行操作

缺點:

  1. 迭代器模式在遍歷的同時更改迭代器所在的集合結構會導致出現異常。所以使用foreach語句只能在對集合進行遍歷,不能在遍歷的同時更改集合中的元素。

七、 總結

到這裡,本博文的內容就介紹結束了,迭代器模式就是抽象一個迭代器類來分離了集合對象的遍歷行為,這樣既可以做到不暴露集合的內部結構,又可讓外部代碼透明地訪問集合內部的數據。

Copyright © Linux教程網 All Rights Reserved