65.9K
CodeProject 正在变化。 阅读更多。
Home

理解并在 C# 中实现迭代器模式

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.82/5 (24投票s)

2012 年 4 月 9 日

CPOL

4分钟阅读

viewsIcon

104530

downloadIcon

782

如何在 C# 中实现迭代器模式

引言

本文旨在解释迭代器模式,并在 C# 中对迭代器模式进行初步实现。本文面向初学者,不使用任何语言内置的迭代功能。

背景

在软件开发中,拥有一个对象集合是非常普遍的。如果我们有一个对象集合,那么我们可能还需要遍历这个集合。大多数语言都提供了对基本集合类型的遍历技术。C# 也包含一些特殊的容器类型,能够保存值的集合(例如:C# 中的 ListArrayList)。这些专门的容器也具有迭代的可能性。C# 容器类是迭代器模式如何实现的最佳示例。

注意:在本文中,我们将不使用任何这些技术。

如果我们想要了解这些迭代器对象的底层工作机制,那么我们可能需要首先理解迭代器模式。迭代器模式背后的思想是将实际的集合对象与遍历逻辑分离。这将使集合对象更轻量级,因为它不必处理所有与迭代相关的功能,并且从用户的角度来看,集合及其迭代方式之间存在清晰的分离。此外,用户不必担心跟踪已遍历的项数、剩余的项数以及是否检查边界条件,因为所有这些都在迭代器对象中完成(因为这些事情将取决于集合对象的底层结构和实现)。

iterator pattern image

GoF 将迭代器模式定义为“提供一种顺序访问聚合对象元素的方法,而无需暴露其底层表示”。为了可视化 GoF 设计(根据我们的实现略作修改)

iterator pattern image

Using the Code

在开始实现之前,让我们试着看看这个图中的每个类代表什么

  • IIterator:这是一个接口,定义了访问和遍历元素的方法。
  • MyIterator:这是 ConcreteIterator,它将实现 Iterator 接口并跟踪聚合对象遍历中的当前位置。
  • IAggregate:这是一个接口,定义了创建 Iterator 对象的方法。
  • MyAggregate:这是 ConcreteAggregate 对象,即,真实的集合位于其中。这个类实现了 IAggregate 创建接口。

创建迭代器接口

现在让我们尝试通过一次实现一个类来实现这个模式。 让我们从编写 IIterator 接口开始。此接口应提供访问和遍历集合对象元素的方法。

IIterator 的实现

interface IIterator
{
    string FirstItem { get;}
    string NextItem{ get;}
    string CurrentItem{ get;}
    bool IsDone { get;}
}

创建聚合(集合)对象的接口

一旦我们准备好 IIterator,就让我们拥有接口 IAggregate。 这将简单地包含创建迭代器的方法。

IAggregate 的实现

interface IAggregate
{
    IIterator GetIterator();
    string this[int itemIndex]{set;get;}
    int Count{get;}
}

编写具体聚合(集合)对象

现在我们已经准备好这两个接口,我们可以定义将保存对象集合的具体类。 让我们创建一个简单的类,它将保存 string 值的集合。我们将使用我们的迭代器来获取这些 string 值。

MyAggregate 的实现

class MyAggregate : IAggregate
{
    List<string> values_ = null;

    public MyAggregate()
    {
        values_ = new List<string>();
    }

    #region IAggregate Members

    public IIterator GetIterator()
    {
        return new MyIterator(this);
    }

    #endregion

    public string this[int itemIndex]
    {
        get
        {
            if (itemIndex < values_.Count)
            {
                return values_[itemIndex];
            }
            else
            {
                return string.Empty;
            }
        }
        set
        {                
            values_.Add(value);                                
        }
    }

    public int Count
    {
        get
        {
            return values_.Count;
        }
    }
}</string>

实现具体迭代器

现在让我们实现 MyIterator,它是 IIterator 的具体类。 通过具体集合类的值进行迭代的实际逻辑将在此类中。

MyIterator 的实现

class MyIterator : IIterator
{
    IAggregate aggregate_ = null;
    int currentIndex_ = 0;

    public MyIterator(IAggregate aggregate)
    {
        aggregate_ = aggregate;
    }

    #region IIterator Members

    public string FirstItem
    {
        get
        {
            currentIndex_ = 0;
            return aggregate_[currentIndex_];
        }
    }

    public string NextItem
    {
        get
        {
            currentIndex_ += 1;

            if (IsDone == false)
            {
                return aggregate_[currentIndex_];
            }
            else
            {
                return string.Empty;
            }
        }
    }

    public string CurrentItem
    {
        get
        {
            return aggregate_[currentIndex_];
        }
    }

    public bool IsDone
    {
        get
        {
            if (currentIndex_ < aggregate_.Count)
            {
                return false;
            }
            return true;
        }
    }

    #endregion
}

所以现在,我们已经为迭代器模式的简单和初步实现准备好了所有构建块。 让我们看看我们如何使用迭代器来访问集合的值。

这是 Main 的实现

class Program
{
    static void Main(string[] args)
    {
        MyAggregate aggr = new MyAggregate();

        aggr[0] = "1";
        aggr[1] = "2";
        aggr[2] = "3";
        aggr[3] = "4";
        aggr[4] = "5";
        aggr[5] = "6";
        aggr[6] = "7";
        aggr[7] = "8";
        aggr[8] = "9";
        aggr[9] = "10";

        IIterator iter = aggr.GetIterator();

        for (string s = iter.FirstItem; iter.IsDone == false;  s = iter.NextItem )
        {
            Console.WriteLine(s);
        }
    }
}

现在我们有了一个迭代器模式的简单实现。 代码中可能存在许多可能的优化,但这里的目的是解释迭代器模式,因此代码以一种简单(也许不是那么高效)的方式编写。

关注点

.NET Framework 和 C# 语言在其代码中深度嵌入了迭代器模式。 IEnumerable 接口实际上是迭代器模式的促进者。 C# 中的泛型和集合类可以通过枚举器进行迭代,这实际上是一个迭代器模式的实现。

我们在本文中没有看到 C# 和 .NET 特定的迭代器模式实现。 使用语言和框架内置的迭代器肯定更有效且不易出错。 本文背后的想法是了解迭代器模式的工作原理,我们在 C# 中实现了一个简单的迭代器模式。

历史

  • 2012 年 4 月 7 日:第一个版本
© . All rights reserved.