Iterator - 迭代器模式

目录

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

前言

  这是一包奥利奥(数组),里面藏了很多块奥利奥饼干(数组中的元素),我将它们放在一个碟子上慢慢排好,从上往下一块块的拿起来(迭代),再一口气吃掉,这就是今天的早餐,也就是要说的 Iterator - 迭代器模式。

回顾

  我们常用的 for 和 foreach,其实就是 MS 给我们封装后的迭代器模式。为什么数组和集合能够使用这两个关键字呢?因为他们都实现了一个接口 IEnumerable,实现了内部方法 GetEnumerator。我们对一个集合,或者是数组进行遍历的同时,也就是数组或集合元素的下标不断递增的一个过程。

  左边的下标 0 表示数组的第一个元素;

  左边的下标 1 表示数组的第二个元素;

  ... ...

  左边的下标 i 表示数组的第i+1个元素;

  最后一个元素就是数组的长度 - 1;

  

UML 类图

代码分析

  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();}}

  dish 作为一个数组,在一开始初始化的时候放置几块奥利奥饼干,通过 GetEnumerator() 可以得到迭代器,在 while 循环中,通过 MoveNext() 可以移动到集合的下一个元素下标,并取出奥利奥饼干,直到超出索引范围(即奥利奥饼干已经吃完)才会终止循环。这就是之前为什么我将 DishIterator 的下标(_index)初始化值为 -1,MoveNext() 方法会先移动光标的位置,再从迭代器的 GetCurrent() 方法取出当前元素的值(根据 MoveNext() 移动后的下标)。

抽象的 UML 类图

思考

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

  观察上述代码,我们发现在 while 循环内只涉及方法 MoveNext() 和 GetCurrent(),不依赖集合本身的 Dish 类对象,在遍历时与集合没有强耦合的关系,遍历和实现进行了分离。

  也就是说,无论集合 Dish 本身如何变化,只要能够正常返回 iterator 迭代器,我们就可以正常遍历。

  设计模式的作用就是帮助我们编写可复用的类。所谓“可复用”,是指将类当成“组件”,当一个组件发生变化时,会尽可能的减少对其他组件的影响,其他组件只需更少的修改或者不需要修改就可以继续正常工作。

  

  【2】为什么我们有 ConcreteEnumerable 和 ConcreteIterator 两个具体类,还要额外创建一层接口呢?

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

  【总结】优先使用抽象类和接口来进行编程,而不要总想着采用具体类来实现编程。


【博主】反骨仔

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

[C# 设计模式] Iterator - 迭代器模式:我与一份奥利奥早餐的故事相关推荐

  1. 设计模式之迭代器模式(Iterator)摘录

    23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于如何创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而 ...

  2. Java设计模式 (1) —— Iterator迭代器模式

    拿到这个话题,首先搞清楚:什么是迭代器? 大家都学过 for-i 循环,for-i循环的本质就是 通过i++ 或者 i-- ,以实现 从数据的一端 一个一个地遍历数据元素,直到另一端的最后一个元素,将 ...

  3. [导入]C#面向对象设计模式纵横谈(18):(行为型模式) Iterator 迭代器模式.zip(8.04 MB)...

    讲座内容: 本培训课程探讨GoF23之 Iterator 迭代器模式的意图.动因.原理.应用场景与C#语言实现,以及该模式在.NET框架程序设计中的具体应用. 课程讲师: 李建忠 上海祝成信息科技有限 ...

  4. 【GOF23设计模式】迭代器模式

    [GOF23设计模式]迭代器模式 来源:http://www.bjsxt.com/  一.[GOF23设计模式]_迭代器模式.JDK内置迭代器.内部类迭代器 1 package com.test.it ...

  5. [转载] Python进阶:设计模式之迭代器模式

    参考链接: Python中的迭代器 在软件开发领域中,人们经常会用到这一个概念--"设计模式"(design pattern),它是一种针对软件设计的共性问题而提出的解决方案.在一 ...

  6. 每日学一个设计模式1——迭代器模式

    引言 精通设计模式是从码农脱颖而出的条件之一.跟着<图解设计模式>这本书学习设计模式,从今天开始,一天总结一个设计模式. 迭代器模式(一个一个遍历) 用处 隐藏遍历集合的内部结构,遍历不同 ...

  7. php迭代器实例,php设计模式之迭代器模式实例分析【星际争霸游戏案例】

    本文实例讲述了php设计模式之迭代器模式.分享给大家供大家参考,具体如下: 星际的任务关一般会有这样的设定:一开始电脑的农民不采矿,如果战斗打响,或者玩家造出第一个兵,电脑的农民开始采矿. 我们自然会 ...

  8. Java 设计模式 Iterator 迭代 模式

    Java 设计模式 Iterator 迭代 模式 Iterator模式用于在数据集合中按照顺序遍历集合. 涉及到的角色 迭代器:负责定义按顺序逐个遍历元素的接口. 具体的迭代器:负责实现迭代器角色定义 ...

  9. 设计模式:迭代器模式(Iterator)

    欢迎支持笔者新作:<深入理解Kafka:核心设计与实践原理>和<RabbitMQ实战指南>,同时欢迎关注笔者的微信公众号:朱小厮的博客. 欢迎跳转到本文的原文链接:https: ...

最新文章

  1. sql 根据多个ID删除表中多行数据
  2. 如何利用简单的Excel操作来预测用户流失?!
  3. HTML/XHTML/HTML5/CSS学习链接
  4. 140.String Compression
  5. 某大厂JVM常见面试题(二)吐血整理
  6. 国外好的软件测试网站
  7. Hawk搜索引擎平台0.6.9测试版(提供下载)
  8. c++笔记(10) 文件输入输出
  9. 分享些我见到的听到的各种创业经历(有成功也有失败)——分析下创业成功要做到哪些...
  10. 利用过滤器防止XSS攻击
  11. ondestroy什么时候调用_程序员最害怕的是什么—函数
  12. 转】 神奇图片解析之旋转的舞女
  13. 基于DFS的拓扑排序算法实现
  14. noi题库 1.5编程基础之循环控制 :题解大礼包20180720
  15. jwplayer html插件,jQuery插件JWPlayer视频播放器用法实例分析
  16. 去除马赛克,有办法了 附运行教程
  17. js prototype原形
  18. vue wath 详细介绍
  19. 内网渗透(五十三)之域控安全和跨域攻击-利用域信任密钥获取目标域控
  20. SUBSTANCE PAINTER质感案例教学 PBR次世代影视游戏场景道具制作 SP金属木头皮革材质渲染...

热门文章

  1. cygwin使用笔记
  2. Effective C++ 读后感
  3. Windows编程—获取操作系统默认浏览器路径
  4. 通过命令行新建qt项目,并编译打包
  5. 【bzoj4007】[JLOI2015]战争调度 暴力+树形背包dp
  6. Mac 如何寻找Mac自带的IDLE
  7. 《C程序设计语言》笔记 (五) 指针与数组
  8. 一个渣渣的随页面滚动改变定位的代码
  9. 《软件工程概论》第四章核心内容
  10. 【移动开发】SparseArray替代HashMap