zoukankan      html  css  js  c++  java
  • C#中FCL迭代器模式的一点问题

    迭代器模式是GOF23种模式中的一种,目的是为了提供对集合的遍历。为什么要实现迭代器模式:

    假设存在一个数组,我们的遍历模式可能是采用依据索引来进行遍历。又假设存在一个HashTable,我们的遍历模式就可能按照键值来进行遍历。无论是哪个集合,如果它们的遍历没有一个公共的接口,那么我们的客户端进行调用的时候,相当于是对具体类型进行了编码。这样以来,当需求变化的时候,就必须修改我们的代码。并且,由于客户端代码过多的关注了集合的内部实现,代码的可移植性就会变得很差,这直接违反了面向对象中的开闭原则。于是,迭代器模式就诞生了。现在,不要管FCL中是如何实现该模式的,我们先来实现一个我们自己的迭代器模式。

    代码清单:

    public class Program
    {
    static void Main(string[] args)
    {
    //使用接口IMyEnumerable代替MyList
    IMyEnumerable list
    = new MyList();
    //得到迭代器,在循环中针对迭代器编码,而不是集合MyList
    IMyEnumerator enumerator
    = list.GetEnumerator();
    for (int i = 0; i < list.Count; i++)
    {
    object current = enumerator.Current;
    enumerator.MoveNext();
    }
    while (enumerator.MoveNext())
    {
    object current = enumerator.Current;
    }
    }
    }

    /// <summary>
    /// 要求所有的迭代器全部实现该接口
    /// </summary>
    interface IMyEnumerator
    {
    bool MoveNext();
    object Current { get; }
    }

    /// <summary>
    /// 要求所有的集合实现该接口
    /// 这样一来,客户端可以针对该接口编码,而无需关注具体的实现
    /// </summary>
    interface IMyEnumerable
    {
    IMyEnumerator GetEnumerator();
    int Count { get; }
    }
    class MyList : IMyEnumerable
    {
    object[] items = new object[10];
    public IMyEnumerator MyEnumerator { get; set; }
    public object this[int i]
    {
    get { return items[i]; }
    set { this.items[i] = value; }
    }
    public int Count
    {
    get { return items.Length; }
    }
    public IMyEnumerator GetEnumerator()
    {
    if (MyEnumerator == null)
    {
    return new MyEnumerator(this);
    }
    return MyEnumerator;
    }
    }

    class MyEnumerator : IMyEnumerator
    {
    int index = 0;
    MyList myList;
    public MyEnumerator(MyList myList)
    {
    this.myList = myList;
    }

    public bool MoveNext()
    {
    if (index + 1 > myList.Count)
    return false;
    else
    {
    index
    ++;
    return true;
    }
    }
    public object Current
    {
    get { return myList[index]; }
    }

    }

    MyList模拟了一个集合类,它继承了接口IMyEnumerable,这样,在客户端进行调用的时候,我们就可以直接使用IMyEnumerable来进行声明变量,如代码中的:

                IMyEnumerable list = new MyList();

    如果未来我们新增了其它的集合类,那么针对list的编码即使不做修改也能运行良好。在IMyEnumerable中声明的GetEnumerator方法返回一个继承了IMyEnuerator的对象。在MyList的内部,我们默认返回MyEnumerator。MyEnumerator就是迭代器的一个实现,如果对于迭代的需求有变化,我们可以重新开发一个迭代器,然后为MyList指定该迭代器就可以了。注意客户端的代码中,迭代的过程我们分别演示了for和while循环。因为使用了迭代器的缘故,两个循环都没有针对MyList编码,而是实现对迭代器的编码。

    理解了我们自己实现的迭代器模式,就相当于理解了FCL中提供的对应模式。其实,上文代码中我们的接口名称中都加入了“My”字样,FCL中有相对应的这类接口,只不过我们为了演示的需要,增删了接口中的部分内容,但是大致的思路是一样的。

    但是,问题也带来了。当集合类型因为某种需求,需要一个自定义迭代器的时候,FCL没有给我们公开这样的接口。所有的FCL集合,无论是泛型还是非泛型集合,都提供了GetEnumerator方法,没有提供SetEnumerator方法。注意到在我自己实现的集合类MyList 中,我公开了迭代器属性:

            public IMyEnumerator MyEnumerator { get; set; }

    这样一来,可以让集合有新的迭代需求的时候,实现自己的迭代器。当然,如果没有为集合对象指定迭代器,那么它会返回一个默认迭代器,如下:

    public IMyEnumerator GetEnumerator()
    {
    if (MyEnumerator == null)
    {
    return new MyEnumerator(this);
    }
    return MyEnumerator;
    }

    公开迭代器属性的好处就是,一旦迭代需求变化,我可以随时扩充我自己的迭代器,只要它继承IMyEnumerator接口。所以,为什么微软提供的FCL不让我们扩充迭代器呢?

  • 相关阅读:
    Laravel 初始化
    ant design pro 左上角 logo 修改
    请求到服务端后是怎么处理的
    Websocket 知识点
    王道数据结构 (7) KMP 算法
    王道数据结构 (6) 简单的模式匹配算法
    王道数据结构 (4) 单链表 删除节点
    王道数据结构 (3) 单链表 插入节点
    王道数据结构 (2) 单链表 尾插法
    王道数据结构 (1) 单链表 头插法
  • 原文地址:https://www.cnblogs.com/luminji/p/1956723.html
Copyright © 2011-2022 走看看