我们都用过电视机遥控器,通过它我们可以进行开机、关机、换台、改变音量等操作。我们可以将电视机看做一个存储电视频道的集合对象,通过遥控器可以对电视机中的频道集合进行操作,例如返回上一个频道、跳转到下一个频道或者跳转到指定的频道等。遥控器的出现,使得用户不需要知道这些频道到底如何存储在电视机中。在软件开发中也存在类似于电视机一样的类,他们可以存储了多个成员对象(元素),这些类通常称为聚合类(Aggregate Class),对应的对象称为聚合对象。为了更加方便地操作这些聚合对象,同时可以很灵活地为聚合对象增加不同的遍历方法,也需要类似于电视机遥控器一样的角色,可以访问一个聚合对象中的元素担忧部需要暴露它的内部结构,这就是我们需要学习的迭代器模式。

迭代器模式(Iterator) 学习难度:★★★☆☆ 使用频率:★★★★★

一、销售管理系统中数据的遍历

Background : M公司为某商场开发了一套销售管理系统,在对该系统进行分析和设计时,M公司开发人员发现经常需要对系统中的商品数据、客户数据等进行遍历,为了复用这些遍历代码,M公司开发人员设计了一个抽象的数据聚合类AbstractObjectList,而将存储商品和客户登记的类作为其子类。AbstractObjectList类结构如下图所示。

在上图中,IList类型的对象objects用于存储数据,AbstractObjectList类的方法说明如下表所示:

AbstractObjectList类的子类ProductList和CustomerList分别用于存储商品数据和客户数据。

  M公司开发人员通过对AbstractObjectList类结构进行分析,发现该设计方案存在以下问题:

  (1)在该类中,AddObject()与RemoveObject()等方法用于管理数据,而GetNextItem()、GetPreviousItem()、IsFirst()等方法又用于遍历数据,导致了聚合类的职责过重,违反了单一职责原则。

  (2)如果将抽象聚合类声明为一个接口,则在这个接口中充斥着大量方法,不利于子类实现,违反了接口隔离原则。

  (3)如果将所有的遍历操作都交给子类来实现,将导致子类代码过于庞大,而且必须暴露AbstractObjectList类的内部存储细节,向子类公开自己的私有属性,否则子类无法实施对数据的遍历,将破坏AbstractObjectList类的封装性。

  如何解决该问题?解决方案之一就是将聚合类中负责遍历数据的方法提取出来,封装到专门的类中,实现数据存储和数据遍历的分离无须暴露聚合类的内部属性即可对其进行操作,这正是迭代器模式的意图所在。

二、迭代器模式概述

2.1 迭代器模式简介

  在软件开发中,经常需要使用聚合对象来存储一系列数据。聚合对象拥有两个职责:一是存储数据,二是遍历数据。从依赖性来看,前者是聚合对象的基本职责,而后者既是可变化的又是可分离的。因此,可以将遍历数据的行为从聚合对象中分离出来,封装在一个被称为“迭代器”的对象中,由迭代器来提供遍历聚合对象内部数据的行为,这将简化聚合对象的设计,更加符合单一职责原则。

迭代器(Iterator)模式:提供一种方法来访问聚合对象,而不用暴露这个对象的内部表示,其别名为游标(Cursor)。迭代器模式是一种对象行为型模式。  

2.2 迭代器模式结构

  (1)Iterator(抽象迭代器):定义了访问和遍历元素的接口,声明了用于遍历数据元素的方法。

  (2)ConcreteIterator(具体迭代器):它实现了抽象迭代器接口,完成对聚合对象的遍历。

  (3)Aggregate(抽象聚合类):用于存储和管理元素对象,声明一个CreateIterator()方法用于创建一个迭代器对象,充当抽象迭代器工厂角色。

  (4)ConcreteAggregate(具体聚合类):实现了在抽象聚合类中声明的CreateIterator()方法,返回一个对应的具体迭代器ConcreteIterator实例。

三、销售管理系统中数据的遍历实现

3.1 重构后的设计结构

  其中,AbstractObjectList充当抽象聚合类,ProductList充当具体聚合类,AbstractIterator充当抽象迭代器,ProductIterator充当具体迭代器。

3.2 重构后的代码实现

  (1)抽象聚合类:AbstractObjectList

    /// <summary>/// 抽象聚合类:AbstractObjectList/// </summary>public abstract class AbstractObjectList{protected IList<object> objectList = new List<object>();public AbstractObjectList (IList<object> objectList){this.objectList = objectList;}public void AddObject(object obj){this.objectList.Add(obj);}public void RemoveObject(object obj){this.objectList.Remove(obj);}public IList<Object> GetObjectList(){return this.objectList;}// 声明创建迭代器对象的抽象工厂方法public abstract AbstractIterator CreateIterator();}

  (2)具体聚合类 - ProductList 与 具体迭代器 - ProductIterator => 这里采用了内部类的方式

    /// <summary>/// 具体聚合类:ProductList/// </summary>public class ProductList : AbstractObjectList{public ProductList(IList<object> objectList) : base(objectList){}public override AbstractIterator CreateIterator(){return new ProductIterator(this);}/// <summary>/// 内部类=>具体迭代器:ProductIterator/// </summary>private class ProductIterator : AbstractIterator{private ProductList productList;private IList<object> products;private int cursor1;    // 定义一个游标,用于记录正向遍历的位置private int cursor2;    // 定义一个游标,用于记录逆向遍历的位置public ProductIterator(ProductList productList){this.productList = productList;this.products = productList.GetObjectList();       // 获取集合对象this.cursor1 = 0;                                                            // 设置正向遍历游标的初始值this.cursor2 = this.products.Count - 1;                 // 设置逆向遍历游标的初始值
            }public object GetNextItem(){return products[cursor1];}public object GetPreviousItem(){return products[cursor2];}public bool IsFirst(){return cursor2 == -1;}public bool IsLast(){return cursor1 == products.Count;}public void Next(){if (cursor1 < products.Count){cursor1++;}}public void Previous(){if (cursor2 > -1){cursor2--;}}}}

  (3)抽象迭代器:AbstractIterator

    /// <summary>/// 抽象迭代器:AbstractIterator/// </summary>public interface AbstractIterator{void Next();                                  // 移动至下一个元素bool IsLast();                               // 判断是否为最后一个元素void Previous();                        // 移动至上一个元素bool IsFirst();                             // 判断是否为第一个元素object GetNextItem();           // 获取下一个元素object GetPreviousItem();   // 获取上一个元素}

  (4)客户端测试

    public class Program{public static void Main(string[] args){IList<object> products = new List<object>();products.Add("倚天剑");products.Add("屠龙刀");products.Add("断肠草");products.Add("葵花宝典");products.Add("四十二章经");AbstractObjectList objectList = new ProductList(products);      // 创建聚合对象AbstractIterator iterator = objectList.CreateIterator();                // 创建迭代器对象
Console.WriteLine("正向遍历");while (!iterator.IsLast()){Console.Write(iterator.GetNextItem() + ",");iterator.Next();}Console.WriteLine();Console.WriteLine("-------------------------------------------------------");Console.WriteLine("逆向遍历");while (!iterator.IsFirst()){Console.Write(iterator.GetPreviousItem() + ",");iterator.Previous();}Console.ReadKey();}}

  F5编译运行后的结果如下图所示:

  

四、迭代器模式小结

4.1 主要优点

  (1)支持以不同方式遍历一个聚合对象,在同一个聚合对象上可以定义多种便利方式。

  (2)增加新的聚合类和迭代器类都很方便 => 无须修改原有代码,符合开闭原则。

4.2 主要缺点

  增加新的聚合类需要对应增加新的迭代器类 => 类的个数会成对增加!

4.3 应用场景

  (1)访问一个聚合对象的内容而无须暴露它的内部表示。

  (2)需要为一个聚合对象提供多种遍历方式。

  (3)重点 => 该模式在.Net中,可以通过实现IEnumberable接口即可,不再需要单独实现! (在.NET下,迭代器模式中的聚集接口和迭代器接口都已经存在了,其中IEnumerator接口扮演的就是迭代器角色,IEnumberable接口则扮演的就是抽象聚集的角色,其中定义了GetEnumerator()方法。)

参考资料

  

  (1)刘伟,《设计模式的艺术—软件开发人员内功修炼之道》

  (2)圣杰,《C#设计模式之迭代器模式》

作者:周旭龙

出处:http://edisonchou.cnblogs.com

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

转载于:https://www.cnblogs.com/edisonchou/p/7442138.html

设计模式的征途—21.迭代器(Iterator)模式相关推荐

  1. 设计模式学习笔记——迭代器(Iterator)模式

    设计模式学习笔记--迭代器(Iterator)模式 @(设计模式)[设计模式, 迭代器模式, iterator, 迭代器] 设计模式学习笔记迭代器Iterator模式 基本介绍 迭代器案例 类图 实现 ...

  2. 设计模式--迭代器(Iterator)模式

    模式定义 提供一中方法顺序访问一个聚合对象中的各个元素,而又不暴露(稳定)该对象的内部表示 类图 要点总结 迭代抽象:访问一个聚合对象的内部而无需暴露它的内部表示 迭代多态:为遍历不同的集合结构提供一 ...

  3. C++之迭代器(Iterator)模式

    0. 简介 迭代器模式是一种行为设计模式, 它可以有效管理数据流动的同时,让用户能在不暴露集合底层表现形式 (列表. 栈和树等) 的情况下遍历集合中所有的元素. 迭代器通常会提供一个获取集合元素的基本 ...

  4. C#设计模式之十五迭代器模式(Iterator Pattern)【行为型】

    一.引言 今天我们开始讲"行为型"设计模式的第三个模式,该模式是[迭代器模式],英文名称是:Iterator Pattern.还是老套路,先从名字上来看看."迭代器模式& ...

  5. 《Head first设计模式》学习笔记 – 迭代器模式

    迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示. 爆炸性新闻:对象村餐厅和对象村煎饼屋合并了! 真是个好消息!现在我们可以在同一个地方,享用煎饼屋美味的煎饼早餐,和好吃 ...

  6. .Net中的设计模式——Iterator模式

    在.Net中,我们很少有机会使用Iterator模式,因为.Net Framework已经运用Iterator模式为所有的集合对象实现了迭代器.我们在遍历集合对象时,喜欢使用C#提供的foreach语 ...

  7. 设计模式——Iterator模式实现研究

    导读:软件设计模式是一种表达.记录和重用软件设计结构和设计经验的新方法,它对反复出现的设计结构的关键特征进行识别.抽象和命名,使重用成功设计和结构更加容易.本文介绍了软件设计模式的特点.描述方式以及在 ...

  8. 设计模式 - 适应设计模式 - Iterator模式(一)

    目录 1.什么是Iterator模式 2.为什么需要Iterator模式 3.Iterator模式的主要角色 4.总结 1.什么是Iterator模式 直接翻译的话其实是叫做迭代器模式,在英文单词中有 ...

  9. 软件设计模式及体系结构之迭代器模式

    前言 1.电视机<→存储电视频道的集合<→聚合类 2.电视机遥控器<→操作电视频道<>迭代器 (Iterator) 3.访问一个聚合对象中的元素但又不需要暴露它的内部 分 ...

最新文章

  1. Ingress 继任者 Gateway API 使用
  2. ThinkPHP 3.2公共类库、应用类库ThinkPHP/Library讲解
  3. 2017年------阿里大神带你详解Dubbo架构设计
  4. 查看和修改Oracle数据库服务器端的字符集
  5. 远控免杀5---Veil免杀
  6. 面向对象分析的三个模型与5个层次
  7. python重写和装饰器_python装饰器
  8. 考研复试考java_2019考研复试经验帖:过来人谈5件“小事”
  9. 不使用临时变量的swap再思考 -- 六种解法
  10. 如何限制修改IP地址
  11. 解决win10学习汇编工具的烦恼——汇编masm的下载和使用(包含可用下载连接)
  12. 数据仓库——概念数据模型
  13. 实现数据结构中的栈---后进先出LIFO
  14. Cron expression must consist of 6 fields
  15. endl 和 \n 的区别
  16. 触动精灵怎么向服务器发送消息,触动精灵 函数说明及使用方法
  17. 星星之火-52:6G十大领域关键技术
  18. neuoj Blurred Pictures(小思维题
  19. c语言程序设计 李俊,深入浅出C语言程序设计(第2版)习题集和编程指导
  20. Android 7.0 适配 FileProvider相机 相册 裁剪的使用

热门文章

  1. OkHttp简化请求封装思路
  2. Kotlin难点解析:extension和this指针
  3. linear-gradient 百分比以及斜角的使用
  4. 《微信公众平台开发最佳实践》——第3章 基 础 接 口 3.1 接收用户消息
  5. nginx通过用户和密码来实现认证功能
  6. 什么是百度竞价创意断句符
  7. SVN钩子--hook
  8. 百度云网盘 360云盘 金山快盘 等 + Git GUI 实现代码版本管理-个人篇
  9. Python学习二——变量和简单数据类型
  10. 您如何查看MySQL用户权限