16.设计模式_迭代器模式

一、引言

  在上篇博文中分享了我对命令模式的理解,命令模式主要是把行为进行抽象成命令,使得请求者的行为和接受者的行为形成低耦合。在一章中,将介绍一下迭代器模式。下面废话不多说了,直接进入本博文的主题。

二、迭代器模式的介绍

  迭代器是针对集合对象而生的,对于集合对象而言,必然涉及到集合元素的添加删除操作,同时也肯定支持遍历集合元素的操作,我们此时可以把遍历操作也放在集合对象中,但这样的话,集合对象就承担太多的责任了,面向对象设计原则中有一条是单一职责原则,所以我们要尽可能地分离这些职责,用不同的类去承担不同的职责。迭代器模式就是用迭代器类来承担遍历集合元素的职责。

2.1 迭代器模式的定义

  迭代器模式提供了一种方法顺序访问一个聚合对象(理解为集合对象)中各个元素,而又无需暴露该对象的内部表示,这样既可以做到不暴露集合的内部结构,又可让外部代码透明地访问集合内部的数据。

2.2 迭代器模式的结构

  既然,迭代器模式承担了遍历集合对象的职责,则该模式自然存在2个类,一个是聚合类,一个是迭代器类。在面向对象涉及原则中还有一条是针对接口编程,所以,在迭代器模式中,抽象了2个接口,一个是聚合接口,另一个是迭代器接口,这样迭代器模式中就四个角色了,具体的类图如下所示:

  从上图可以看出,迭代器模式由以下角色组成:

  • 迭代器角色(Iterator):迭代器角色负责定义访问和遍历元素的接口
  • 具体迭代器角色(Concrete Iteraror):具体迭代器角色实现了迭代器接口,并需要记录遍历中的当前位置。
  • 聚合角色(Aggregate):聚合角色负责定义获得迭代器角色的接口
  • 具体聚合角色(Concrete Aggregate):具体聚合角色实现聚合角色接口。

2.3 迭代器模式的实现

  介绍完迭代器模式之后,下面就具体看看迭代器模式的实现,具体实现代码如下:

  1  // 抽象聚合类
  2     public interface IListCollection
  3     {
  4         Iterator GetIterator();
  5     }
  6
  7     // 迭代器抽象类
  8     public interface Iterator
  9     {
 10         bool MoveNext();
 11         Object GetCurrent();
 12         void Next();
 13         void Reset();
 14     }
 15
 16     // 具体聚合类
 17     public class ConcreteList : IListCollection
 18     {
 19         int[] collection;
 20         public ConcreteList()
 21         {
 22             collection = new int[] { 2, 4, 6, 8 };
 23         }
 24
 25         public Iterator GetIterator()
 26         {
 27             return new ConcreteIterator(this);
 28         }
 29
 30         public int Length
 31         {
 32             get { return collection.Length; }
 33         }
 34
 35         public int GetElement(int index)
 36         {
 37             return collection[index];
 38         }
 39     }
 40
 41     // 具体迭代器类
 42     public class ConcreteIterator : Iterator
 43     {
 44         // 迭代器要集合对象进行遍历操作,自然就需要引用集合对象
 45         private ConcreteList _list;
 46         private int _index;
 47
 48         public ConcreteIterator(ConcreteList list)
 49         {
 50             _list = list;
 51             _index = 0;
 52         }
 53
 54
 55         public bool MoveNext()
 56         {
 57             if (_index < _list.Length)
 58             {
 59                 return true;
 60             }
 61             return false;
 62         }
 63
 64         public Object GetCurrent()
 65         {
 66             return _list.GetElement(_index);
 67         }
 68
 69         public void Reset()
 70         {
 71             _index = 0;
 72         }
 73
 74         public void Next()
 75         {
 76             if (_index < _list.Length)
 77             {
 78                 _index++;
 79             }
 80
 81         }
 82     }
 83
 84     // 客户端
 85     class Program
 86     {
 87         static void Main(string[] args)
 88         {
 89             Iterator iterator;
 90             IListCollection list = new ConcreteList();
 91             iterator = list.GetIterator();
 92
 93             while (iterator.MoveNext())
 94             {
 95                 int i = (int)iterator.GetCurrent();
 96                 Console.WriteLine(i.ToString());
 97                 iterator.Next();
 98             }
 99
100             Console.Read();
101         }
102     }

自然,上面代码的运行结果也是对集合每个元素的输出,具体运行结果如下图所示:

三、.NET中迭代器模式的应用

  在.NET下,迭代器模式中的聚集接口和迭代器接口都已经存在了,其中IEnumerator接口扮演的就是迭代器角色,IEnumberable接口则扮演的就是抽象聚集的角色,只有一个GetEnumerator()方法,关于这两个接口的定义可以自行参考MSDN。在.NET 1.0中,.NET 类库中很多集合都已经实现了迭代器模式,大家可以用反编译工具Reflector来查看下mscorlib程序集下的System.Collections命名空间下的类,这里给出ArrayList的定义代码,具体实现代码可以自行用反编译工具查看,具体代码如下所示:

 1 public class ArrayList : IList, ICollection, IEnumerable, ICloneable
 2 {
 3     // Fields
 4     private const int _defaultCapacity = 4;
 5     private object[] _items;
 6     private int _size;
 7     [NonSerialized]
 8     private object _syncRoot;
 9     private int _version;
10     private static readonly object[] emptyArray;
11
12     public virtual IEnumerator GetEnumerator();
13     public virtual IEnumerator GetEnumerator(int index, int count);
14
15     // Properties
16     public virtual int Capacity { get; set; }
17     public virtual int Count { get; }
18     ..............// 更多代码请自行用反编译工具Reflector查看
19 }

  通过查看源码你可以发现,ArrayList中迭代器的实现与我们前面给出的示例代码非常相似。然而,在.NET 2.0中,由于有了yield return关键字,实现迭代器模式就更简单了,关于迭代器的更多内容可以参考我的这篇博文

四、迭代器模式的适用场景

  在下面的情况下可以考虑使用迭代器模式:

  • 系统需要访问一个聚合对象的内容而无需暴露它的内部表示。
  • 系统需要支持对聚合对象的多种遍历。
  • 系统需要为不同的聚合结构提供一个统一的接口。

五、迭代器模式的优缺点

  由于迭代器承担了遍历集合的职责,从而有以下的优点:

  • 迭代器模式使得访问一个聚合对象的内容而无需暴露它的内部表示,即迭代抽象。
  • 迭代器模式为遍历不同的集合结构提供了一个统一的接口,从而支持同样的算法在不同的集合结构上进行操作

  迭代器模式存在的缺陷:

  • 迭代器模式在遍历的同时更改迭代器所在的集合结构会导致出现异常。所以使用foreach语句只能在对集合进行遍历,不能在遍历的同时更改集合中的元素。

六、总结

  到这里,本博文的内容就介绍结束了,迭代器模式就是抽象一个迭代器类来分离了集合对象的遍历行为,这样既可以做到不暴露集合的内部结构,又可让外部代码透明地访问集合内部的数据。在一篇博文中将为大家介绍观察者模式。

时间: 2024-10-20 10:45:36

16.设计模式_迭代器模式的相关文章

大话设计模式_迭代器模式(Java代码)

迭代器模式:提供一个方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示 简单描述:提供一个单独的接口遍历聚集类对象中的成员,以实现聚集对象的隐藏和内部数据供外部访问 大话设计模式中的截图: 我觉得以上面的图示进行编码会暴露ConcreteAggregate中的内部信息(ConcreteIerator可以访问聚集类中的成员,那表示其他类也可以和ConcreteIerator一样进行相同的访问),所以我以另外一种形式实现迭代器(即内部类的方式,和Java中的ArrayList类似) 代码

java设计模式_迭代器模式

/**  * @Title: Aggregate.java  * @Package com.wangbiao.design  * @Description: TODO   * @author wangbiao     * @date 2014-9-20 下午05:02:00   * @version V1.0  */ package com.wangbiao.design.iterator; import java.io.ObjectInputStream.GetField; import ja

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

来源:http://www.bjsxt.com/ 一.[GOF23设计模式]_迭代器模式.JDK内置迭代器.内部类迭代器 1 package com.test.iterator; 2 /** 3 * 自定义的迭代器接口 4 */ 5 public interface MyIterator { 6 void first(); //将游标指向第一个元素 7 void next(); //将游标指向下一个元素 8 boolean hasNext(); //判断是否存在下一个元素 9 10 boolea

大话设计模式_备忘录模式(Java代码)

备忘录模式:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可将该对象恢复到原先保存的状态. 简单描述:一个Memento类,代表Originator中要备份的属性.Originator负责生成备份和还原备份,CareTaker负责存储备份 大话设计模式中的截图: 例子代码: Memento类: 1 package com.longsheng.memento; 2 3 public class Memento { 4 5 private String sta

大话设计模式_解释器模式(Java代码)

解释器模式:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子. 简单描述:一个AbstractExpression类,多个子类,存在一个Interpret方法,转义Context对象的信息.客户端根据信息实例化不同的Expression类,并调用其转义方法(这个过程可以使用简单工厂+反射进行) 大话设计模式中的截图: 代码例子: 假设HTML代码解释器: (1)第一类标签<HTML>(开始)/<HEAD>(头信息)/<BODY&g

大话设计模式_原型模式(Java代码)

原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象 简单描述:即通过实现接口Cloneable重写方法clone(),使得创建新的拷贝对象不需要一个成员一个成员的重新复制,而且可以提高创建对象的效率 Java中要想实现拷贝使用clone()方法,类必须实现Cloneable接口,并且重写Object类中的clone()方法,调用父类的clone()方法即可实现浅复制 代码如下: WorkExperience类: 1 package com.longsheng.prototy

大话设计模式_模板方法模式(Java代码)

模板方法模式:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤 简单描述:多个类的行为是差不多的,只是某些局部不一样,则交由父类中抽象出这些子类中相同的部分,父类中定义出不同的部分的接口(方法),这些不同部分的方法则由子类去实现,通过多态,实现代码的重用 大话设计模式中的截图: 例子代码: AbstractClass类: 1 package com.longsheng.templatemethod; 2 3 public

大话设计模式_状态模式(Java代码)

状态模式:当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类. 简单描述:一个Context类(存有一个抽象状态State引用),调用状态类的方法.State的具体类方法中会判断Context类的状态(如时间),满足一个状态则执行相应动作,否则把Context的State引用指向下一个状态类,由下一个状态类决定相应行为 大话设计模式中的截图: 例子代码: Work类(Context): 1 package com.longsheng.state; 2 3 public cla

大话设计模式_建造者模式(Java代码)

建造者模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示 简单描述:1个产品类(可有可无,关键是建造流程),1个抽象建造步骤类,多个具体建造子类(不同的类建造不同的产品),1个指挥者(用于规定建造流程),客户端指定需要建造的具体类型,由指挥者建造好之后,建造者子类返回对应产品给客户 大话设计模式中的截图: 例子代码: Product类: 1 package com.longsheng.builder; 2 3 public class Product { 4 5 pr