zoukankan      html  css  js  c++  java
  • 步步为营 .NET 设计模式学习笔记 十一、Iterator(迭代器模式)

    概述

    在面向对象的软件设计中,我们经常会遇到一类集合对象,这类集合对象的内部结构可能有着各种各样的实现,但是归结起来,无非有两点是需要我们去关心的:一是集合内部的数据存储结构,二是遍历集合内部的数据。面向对象设计原则中有一条是类的单一职责原则,所以我们要尽可能的去分解这些职责,用不同的类去承担不同的职责。Iterator模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可让外部代码透明的访问集合内部的数据。

    为什么要写

    但现在C#的Foreach in己经替代了迭代器模式的功能,但是作为学习设计模式来说,还是很有好处的.

    意图

    提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。[GOF 《设计模式》]

    结构图

    <Design Pattern>Iterator模式结构图如下:

    alt

    图1 Iterator模式结构图

    迭代器模式由以下角色组成: 
    1.迭代器角色(Iterator):迭代器角色负责定义访问和遍历元素的接口。 
    2.具体迭代器角色(Concrete Iterator):具体迭代器角色要实现迭代器接口,并要记录遍历中的当前位置。 
    3.容器角色(Container):容器角色负责提供创建具体迭代器角色的接口。 
    4.具体容器角色(Concrete Container):具体容器角色实现创建具体迭代器角色的接口——这个具体迭代器角色于该容器的结构相关。

    生活中的例子

    迭代器提供一种方法顺序访问一个集合对象中各个元素,而又不需要暴露该对象的内部表示。在早期的电视机中,一个拨盘用来改变频道。当改变频道时,需要手工转动拨盘移过每一个频道,而不论这个频道是否有信号。现在的电视机,使用[后一个]和[前一个]按钮。当按下[后一个]按钮时,将切换到下一个预置的频道。想象一下在陌生的城市中的旅店中看电视。当改变频道时,重要的不是几频道,而是节目内容。如果对一个频道的节目不感兴趣,那么可以换下一个频道,而不需要知道它是几频道。

    alt

    图2 使用选频器做例子的Iterator模式对象图

    示例用例图:

    超市顾客排队结帐,收银员一个一个顺序的结帐,正好符合我们的迭代器模式,以下是用例图:

    image

    代码设计:

    先创建Cashier.cs:

    01 /// <summary>
    02 /// Cashier
    03 /// </summary>
    04 public abstract class Cashier
    05 {
    06     /// <summary>
    07     /// First item
    08     /// </summary>
    09     /// <returns></returns>
    10     public abstract object First();
    11  
    12     /// <summary>
    13     /// Next item
    14     /// </summary>
    15     /// <returns></returns>
    16     public abstract object Next();
    17  
    18     /// <summary>
    19     /// Is complete
    20     /// </summary>
    21     /// <returns></returns>
    22     public abstract bool IsComplete();
    23  
    24     /// <summary>
    25     /// Current item
    26     /// </summary>
    27     /// <returns></returns>
    28     public abstract object CurrentCustomer();
    29 }

    再创建IConsumer.cs:

    01 /// <summary>
    02 /// Create Cashier class
    03 /// </summary>
    04 public abstract class IConsumer
    05 {
    06     /// <summary>
    07     /// Creaate Cashier
    08     /// </summary>
    09     /// <returns></returns>
    10     public abstract Cashier CreateCashier();
    11 }

    再创建Consumer.cs:

    01 /// <summary>
    02 /// Consumer
    03 /// </summary>
    04 public  class Consumer:IConsumer
    05 {
    06     private IList<object> items = new List<object>();
    07  
    08     public override Cashier CreateCashier()
    09     {
    10         return new CLoseAccount(this);
    11     }
    12  
    13     public int Count
    14     {
    15         get return items.Count; }
    16     }
    17  
    18     public object this[int index]
    19     {
    20         get return items[index]; }
    21         set { items.Insert(index,value); }
    22     }
    23 }

    再创建CLoseAccount.cs:

    01 /// <summary>
    02 /// close account
    03 /// </summary>
    04 public class CLoseAccount : Cashier
    05 {
    06     private Consumer CurrentConsumer;
    07  
    08     private int Current = 0;
    09  
    10     public override object First()
    11     {
    12         return CurrentConsumer[0];
    13     }
    14  
    15     public override object Next()
    16     {
    17         ++Current;
    18         if (Current < CurrentConsumer.Count)
    19             return CurrentConsumer[Current];
    20         else
    21             return (object)null;
    22     }
    23  
    24     public override bool IsComplete()
    25     {
    26         return CurrentConsumer.Count > Current ? true false;
    27     }
    28  
    29     public override object CurrentCustomer()
    30     {
    31         return CurrentConsumer[Current];
    32     }
    33  
    34     public CLoseAccount(Consumer consumer)
    35     {
    36         this.CurrentConsumer = consumer;
    37     }
    38 }

    最后调用:

    01 public partial class Run : Form
    02  {
    03      public Run()
    04      {
    05          InitializeComponent();
    06      }
    07  
    08      private void btnRun_Click(object sender, EventArgs e)
    09      {
    10  
    11  
    12          Consumer consumer = new Consumer();
    13          consumer[0] = "顾客A";
    14          consumer[1] = "顾客B";
    15          consumer[2] = "顾客C";
    16          consumer[3] = "顾客D";
    17          consumer[4] = "顾客E";
    18          consumer[5] = "顾客F";
    19          consumer[6] = "顾客G";
    20          consumer[7] = "顾客H";
    21          Cashier cashier = new CLoseAccount(consumer);
    22          object custom = cashier.First();
    23          rtbResult.AppendText("顾客排队结帐开始.\n");
    24          while (cashier.IsComplete())
    25          {
    26              rtbResult.AppendText(string.Format("{0}正在结帐.\n", cashier.CurrentCustomer()));
    27              cashier.Next();
    28          }
    29          rtbResult.AppendText("结帐完成.\n");
    30      }
    31  }

    结果如下图:

    image

    效果及实现要点

    1.迭代抽象:访问一个聚合对象的内容而无需暴露它的内部表示。

    2.迭代多态:为遍历不同的集合结构提供一个统一的接口,从而支持同样的算法在不同的集合结构上进行操作。

    3.迭代器的健壮性考虑:遍历的同时更改迭代器所在的集合结构,会导致问题。

    适用性

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

    2.支持对聚合对象的多种遍历。

    3.为遍历不同的聚合结构提供一个统一的接口(即, 支持多态迭代)。

    优点: 
    1.支持以不同的方式遍历一个容器角色。根据实现方式的不同,效果上会有差别。 
    2.简化了容器的接口。但是在IList中为了提高可扩展性,容器还是提供了遍历的接口。 
    3.对同一个容器对象,可以同时进行多个遍历。因为遍历状态是保存在每一个迭代器对象中的。 
    总结

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

  • 相关阅读:
    【STL】各容器成员对比表
    windows笔记页文件支持的内存映射文件
    windows笔记【内核对象线程同步】线程同步对象速查表
    windows笔记虚拟内存
    windows笔记使用内存映射文件在进程之间共享数据
    svn个人服务端
    解决安装Visual Studio .NET 2003 时FrontPage 2000 WEB 扩展客户端 安装失败
    vc6.0转vs2008连接错误
    Sublime Text插件推荐
    末日了,说出你的梦想、愿望还有遗憾吧。
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2021666.html
Copyright © 2011-2022 走看看