[C# 设计模式] Iterator – 迭代器模式:我跟平卖奥利奥早餐的故事

Iterator – 迭代器模式

 

目录

  • 前言
  • 回顾
  • UML 类图
  • 代码分析
  • 抽象的 UML 类图
  • 思考

 

前言

  这是平等担保奥利奥(数组),里面藏了重重片奥利奥饼干(数组中之要素),我用其在一个碟上慢慢消除好,从达成通往生一块块的以起来(迭代),再同人暴吃少,这就是今日的早餐,也即是要说的 Iterator

  • 迭代器模式。

图片 1图片 2

 

 

回顾

  我们常因此的 for 和 foreach,其实就算是 MS
给咱封装后的迭代器模式。为什么数组和集纳能够以即时点儿单重点字呢?因为她们都落实了一个接口
IEnumerable,实现了里面方法 GetEnumerator。我们针对一个凑合,或者是数组进行遍历的以,也尽管是数组或集合元素的下标不断递增的一个进程。

图片 3

  左边的下标 0
表示数组的率先个元素;

  左边的下标 1
表示数组的亚独要素;

  … …

  左边的下标 i
表示数组的第i+1单因素;

  最后一个要素即是数组的尺寸 –
1;

  

 UML 类图

图片 4

 图

图片 5

 

代码分析

   IEnumerable 接口

    interface IEnumerable
    {
        IEnumerator GetEnumerator();
    }

  这里仅仅发生一个术 GetEnumerator(),该办法可很成一个遍历集合的元素的迭代器。通过该迭代器,就好进行联谊合元素的遍历了。

 

  IEnumerator 接口

    interface IEnumerator
    {
        bool MoveNext();

        object GetCurrent();
    }

  实现该接口的实例可以变成迭代器。这里出个别个措施:
MoveNext(),GetCurrent()。

  MoveNext():移动及下一个元素的下标,如果是拖欠下标(没有盖索引位置),则回
true。主要用来终止循环条件。

  GetCurrent():获取当前集合元素的价,不过这里因归的品类也
object,可能用开展强转,当然,你也可择采取泛型。

 

  Dish.cs 类(碟子)

    class Dish : IEnumerable
    {
        private readonly List<Aoliao> _aoliaos;

        public Dish()
        {
            _aoliaos = new List<Aoliao>();
        }

        public IEnumerator GetEnumerator()
        {
            return new DishIterator(this);
        }

        public void AppendAoliao(Aoliao aoliao)
        {
            _aoliaos.Add(aoliao);
        }

        public int GetCount()
        {
            return _aoliaos.Count;
        }

        public Aoliao GetAoliao(int index)
        {
            if (index >= GetCount())
            {
                throw new IndexOutOfRangeException();
            }

            return _aoliaos[index];
        }
    }

  这是一个碟子类,因为其实现了 IEnumerable
接口,我管它们作为集合,用于放置拆起来包后的奥利奥饼干。

  这里的构造函数,进行针对 List<Aoliao> 进行联谊的初始化。

  AppendAoliao(Aoliao
aoliao):在原本的集结中增新元素,在放置好的奥利奥饼干后再度补充加相同片新的奥利奥饼干。

  GetCount():获取集合的个数,获取碟子上奥利奥饼干的到底个数。

  GetAoliao(int index):根据下标获取集合中之素。

 

   DishIterator.cs 类(碟子迭代器)

    class DishIterator : IEnumerator
    {
        private int _index;
        private readonly Dish _dish;

        public DishIterator(Dish cookie)
        {
            _index = -1;
            _dish = cookie;
        }

        public bool MoveNext()
        {
            _index++;
            return _index < _dish.GetCount();
        }

        public object GetCurrent()
        {
            try
            {
                return _dish.GetAoliao(_index);
            }
            catch (IndexOutOfRangeException)
            {
                throw new InvalidOperationException();
            }
        }
    }

  该类实现了 IEnumerator 接口,作为迭代器的一个实例对象,用于遍历 Dish
对象内集聚的一个迭代器对象,这里有零星只字段:

  _index:用于指定数组元素的下标,递增,注意,这里自己选择被下标从 -1
开始。

  _dish:保存对 Dish 类的一个引用。

  MoveNext():移动到下一个因素的下标,递增下标
_index,假如索引超出界限则归
false,从此处可以查出奥利奥饼干有没有发出吃了却。

  GetCurrent():获取当前元素,根据下标 _index。

 

  Aoliao.cs 类(奥利奥饼干)

    class Aoliao
    {
        /// <summary>
        /// 味道
        /// </summary>
        public bool Taste { get; set; }
    }

  这里的 Taste 属性,我特用于标识它是不是好吃。

  

  Main.cs 类

    class Program
    {
        static void Main(string[] args)
        {
            var dish = new Dish();
            dish.AppendAoliao(new Aoliao() { Taste = true });
            dish.AppendAoliao(new Aoliao() { Taste = true });
            dish.AppendAoliao(new Aoliao() { Taste = true });

            var iterator = dish.GetEnumerator();
            while (iterator.MoveNext())
            {
                var aoliao = (Aoliao)iterator.GetCurrent();
                Console.WriteLine("味道: " + aoliao.Taste);
            }

            Console.Read();
        }
    }

图片 6

 

  dish
作为一个往往组,在同等起来初始化的时节放置几块奥利奥饼干,通过 GetEnumerator()
可以收获迭代器,在 while 循环中,通过 MoveNext()
可以走至集结的产一个因素下标,并取出奥利奥饼干,直到超出索引范围(即奥利奥饼干已经吃了)才见面停下循环。这虽是前为什么我以 DishIterator
的下标(_index)初始化值为 -1,MoveNext()
方法会先走光标的岗位,再起迭代器的 GetCurrent()
方法取出即因素的价值(根据 MoveNext() 移动后的下标)。

 

抽象的 UML 类图

图片 7

图片 8

 

思考

  【1】为什么要下 Iterator
迭代器模式为?对于集合,或者数组,我们一直使用 for 和 foreach
不就是可以了邪?

图片 9

  观察上述代码,我们发现于 while 循环外只有提到艺术 MoveNext() 和
GetCurrent(),不借助集合本身的 Dish
类对象,在一切历时与聚集没有强耦合的关联,遍历和落实进行了离别。

  也就是说,无论集合 Dish 本身如何变化,只要会健康返回 iterator
迭代器,我们尽管足以正常遍历。

  设计模式的意就是是帮我们编辑而复用的切近。所谓“可复用”,是依将看似当成“组件”,当一个零件发生变化时,会尽可能的回落对任何零件的影响,其他零件只需要还不见之修改或者无需要修改就好继承健康干活。

  

  【2】为什么我们发出 ConcreteEnumerable 和 ConcreteIterator
两个具体类,还要额外创建同层接口也?

  我们连幻想着以实体类来缓解遇到的具备题目。如果仅使具体类来缓解问题,很易增加类之间的强耦合度,这部分类也难当成组件多次用到。为了降低类之间的耦合度,为了增加类的使用度,从而引入了抽象类和接口。

 

   【总结】优先采取抽象类和接口来进展编程,而毫不总想着下具体类来促成编程。

 

 


【博主】反骨仔

【原文】http://www.cnblogs.com/liqingwen/p/6550794.html 

 

相关文章