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

    http://u.huoban001.com/space.php
  • 相关阅读:
    LeetCode 275. H-Index II
    LeetCode 274. H-Index
    LeetCode Gray Code
    LeetCode 260. Single Number III
    LeetCode Word Pattern
    LeetCode Nim Game
    LeetCode 128. Longest Consecutive Sequence
    LeetCode 208. Implement Trie (Prefix Tree)
    LeetCode 130. Surrounded Regions
    LeetCode 200. Number of Islands
  • 原文地址:https://www.cnblogs.com/zpq521/p/2067520.html
Copyright © 2011-2022 走看看