设计模式之迭代器模式

迭代器模式 Iterator

Intro

迭代器模式,提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。

迭代器模式是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可以让外部代码透明地访问集合内部的数据。

使用场景

当你需要访问一个聚集对象,而且不管这些对象是什么都需要遍历的时候,你就应该考虑用迭代器模式。

当你需要对聚集有多种方式遍历时,可以考虑用迭代器模式。

实现方式

如果要自己实现需要有下面几个类:

一个迭代器抽象类(或接口)

一个聚集抽象类(或接口)

具体实现的迭代器类

具体实现的聚集类

Sample

public abstract class Iterator
{
    public abstract object First();

    public abstract object Next();

    public abstract bool IsDone();

    public abstract object CurrentItem();
}

public class ConcreteIterator : Iterator
{
    private readonly ConcreteAggregate _aggregate;
    private int _current = 0;

    public ConcreteIterator(ConcreteAggregate aggregate) => _aggregate = aggregate;

    public override object First()
    {
        return _aggregate[0];
    }

    public override object Next()
    {
        _current++;
        return _current >= _aggregate.TotalCount ? null : _aggregate[_current];
    }

    public override bool IsDone() => _current >= _aggregate.TotalCount;

    public override object CurrentItem() => _aggregate[_current];
}

public abstract class Aggregate
{
    /// <summary>
    /// 创建迭代器
    /// </summary>
    /// <returns></returns>
    public abstract Iterator CreateIterator();
}

public class ConcreteAggregate : Aggregate
{
    private readonly IList<object> _items = new List<object>();

    public override Iterator CreateIterator()
    {
        return new ConcreteIterator(this);
    }

    public int TotalCount => _items.Count;

    public object this[int index]
    {
        get => _items[index];
        set => _items.Insert(index,value);
    }
}


var aggregate = new ConcreteAggregate
{
    [0] = "大鸟",[1] = "小菜",[2] = "行李",[3] = "老外",[4] = "公交员工",[5] = "小偷"
};

Iterator iterator = new ConcreteIterator(aggregate);
do
{
    Console.WriteLine($"{iterator.CurrentItem()} 请买车票");
    iterator.Next();
} while (!iterator.IsDone());

More

需要注意的是,使用迭代器模式遍历集合时,不要对集合进行增加元素或者删除元素操作

在 C# 中实现 IEnumerable 接口就可以比较方便的实现一个迭代器,foreach 就是迭代器的一个语法糖

来看一下 IEnumerabe 的定义:

// 聚集抽象
public interface IEnumerable
{
    /// <summary>Returns an enumerator that iterates through a collection.</summary>
    /// <returns>An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.</returns>
    IEnumerator GetEnumerator();
}

// 迭代器抽象
public interface IEnumerator
{
    /// <summary>Advances the enumerator to the next element of the collection.</summary>
    /// <returns>
    /// <see langword="true" /> if the enumerator was successfully advanced to the next element; <see langword="false" /> if the enumerator has passed the end of the collection.</returns>
    /// <exception cref="T:system.invalidOperationException">The collection was modified after the enumerator was created.</exception>
    bool MoveNext();

    /// <summary>Gets the element in the collection at the current position of the enumerator.</summary>
    /// <returns>The element in the collection at the current position of the enumerator.</returns>
    object Current { get; }

    /// <summary>Sets the enumerator to its initial position,which is before the first element in the collection.</summary>
    /// <exception cref="T:system.invalidOperationException">The collection was modified after the enumerator was created.</exception>
    void Reset();
}

最后留个思考题给你,List 在 foreach 的时候如果删除一个元素会发生什么?内部是怎么样实现的呢? 可以自己实践一下

Reference

相关文章

目录简介使用JS互操作使用ClipLazor库创建项目使用方法简单测...
目录简介快速入门安装 NuGet 包实体类User数据库类DbFactory...
本文实现一个简单的配置类,原理比较简单,适用于一些小型项...
C#中Description特性主要用于枚举和属性,方法比较简单,记录...
[TOC] # 原理简介 本文参考[C#/WPF/WinForm/程序实现软件开机...
目录简介获取 HTML 文档解析 HTML 文档测试补充:使用 CSS 选...