.NET设计模式(18):迭代器模式(Iterator Pattern)
概述
在面向对象的软件设计中,我们经常会遇到一类集合对象,这类集合对象的内部结构可能有着各种各样的实现,但是归结起来,无非有两点是需要我们去关心的:一是集合内部的数据存储结构,二是遍历集合内部的数据。面向对象设计原则中有一条是类的单一职责原则,所以我们要尽可能的去分解这些职责,用不同的类去承担不同的职责。Iterator模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可让外部代码透明的访问集合内部的数据。
意图
提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。[GOF 《设计模式》]
结构图
Iterator模式结构图如下:
图1 Iterator模式结构图
生活中的例子
迭代器提供一种方法顺序访问一个集合对象中各个元素,而又不需要暴露该对象的内部表示。在早期的电视机中,一个拨盘用来改变频道。当改变频道时,需要手工转动拨盘移过每一个频道,而不论这个频道是否有信号。现在的电视机,使用[后一个]和[前一个]按钮。当按下[后一个]按钮时,将切换到下一个预置的频道。想象一下在陌生的城市中的旅店中看电视。当改变频道时,重要的不是几频道,而是节目内容。如果对一个频道的节目不感兴趣,那么可以换下一个频道,而不需要知道它是几频道。
图2 使用选频器做例子的Iterator模式对象图
Iterator模式解说
在面向对象的软件设计中,我们经常会遇到一类集合对象,这类集合对象的内部结构可能有着各种各样的实现,但是归结起来,无非有两点是需要我们去关心的:一是集合内部的数据存储结构,二是遍历集合内部的数据。面向对象设计原则中有一条是类的单一职责原则,所以我们要尽可能的去分解这些职责,用不同的类去承担不同的职责。Iterator模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可让外部代码透明的访问集合内部的数据。下面看一个简单的示意性例子,类结构图如下:
图3 示例代码结构图
首先有一个抽象的聚集,所谓的聚集就是就是数据的集合,可以循环去访问它。它只有一个方法GetIterator()让子类去实现,用来获得一个迭代器对象。











抽象的迭代器,它是用来访问聚集的类,封装了一些方法,用来把聚集中的数据按顺序读取出来。通常会有MoveNext()、CurrentItem()、Fisrt()、Next()等几个方法让子类去实现。
















具体的聚集,它实现了抽象聚集中的唯一的方法,同时在里面保存了一组数据,这里我们加上Length属性和GetElement()方法是为了便于访问聚集中的数据。


































具体迭代器,实现了抽象迭代器中的四个方法,在它的构造函数中需要接受一个具体聚集类型的参数,在这里面我们可以根据实际的情况去编写不同的迭代方式。























































简单的客户端程序调用:
































一个简单的迭代器示例就结束了,这里我们并没有利用任何的.NET特性,在C#中,实现Iterator模式已经不需要这么麻烦了,已经C#语言本身就有一些特定的实现,下面会说到。
.NET中的Iterator模式
在.NET下实现Iterator模式,对于聚集接口和迭代器接口已经存在了,其中IEnumerator扮演的就是迭代器的角色,它的实现如下:













属性Current返回当前集合中的元素,Reset()方法恢复初始化指向的位置,MoveNext()方法返回值true表示迭代器成功前进到集合中的下一个元素,返回值false表示已经位于集合的末尾。能够提供元素遍历的集合对象,在.Net中都实现了IEnumerator接口。
IEnumerable则扮演的就是抽象聚集的角色,只有一个GetEnumerator()方法,如果集合对象需要具备跌代遍历的功能,就必须实现该接口。





下面看一个在.NET1.1下的迭代器例子,Person类是一个可枚举的类。PersonsEnumerator类是一个枚举器类。这个例子来自于http://www.theserverside.net/,被我简单的改造了一下。
































































来看客户端代码的调用:















程序将输出:







现在我们分析编译器在执行foreach语句时到底做了什么,它执行的代码大致如下:


















可以看到这段代码跟我们最前面提到的示例代码非常的相似。同时在这个例子中,我们把大部分的精力都花在了实现迭代器和可迭代的类上面,在.NET2.0下面,由于有了yield return关键字,实现起来将更加的简单优雅。下面我们把刚才的例子在2.0下重新实现一遍:


































程序将输出:







实现相同的功能,由于有了yield return关键字,变得非常的简单。好了,关于.NET中的Iterator模式就说这么多了,更详细的内容大家可以参考相关的资料。
效果及实现要点
1.迭代抽象:访问一个聚合对象的内容而无需暴露它的内部表示。
2.迭代多态:为遍历不同的集合结构提供一个统一的接口,从而支持同样的算法在不同的集合结构上进行操作。
3.迭代器的健壮性考虑:遍历的同时更改迭代器所在的集合结构,会导致问题。
适用性
1.访问一个聚合对象的内容而无需暴露它的内部表示。
2.支持对聚合对象的多种遍历。
3.为遍历不同的聚合结构提供一个统一的接口(即, 支持多态迭代)。
总结
Iterator模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可让外部代码透明的访问集合内部的数据。
参考资料
Erich Gamma等,《设计模式:可复用面向对象软件的基础》,机械工业出版社
Robert C.Martin,《敏捷软件开发:原则、模式与实践》,清华大学出版社
阎宏,《Java与模式》,电子工业出版社
Alan Shalloway James R. Trott,《Design Patterns Explained》,中国电力出版社
MSDN WebCast 《C#面向对象设计模式纵横谈(18):Iterator 迭代器模式(行为型模式)》
设计模式21:Iterator Pattern (迭代器模式)
可以查看英文原文:http://www.dofactory.com/Patterns/PatternIterator.aspx
一、迭代器模式:Iterator Pattern
Define:Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
定义:提供一种方式可以连续的访问几何对象的所有元素而无须关注内在的描述方式。
二、UML图
- Iterator (AbstractIterator)
- 定义一个访问和操作元素的接口
- ConcreteIterator (Iterator)
- 实现迭代器的接口
- keeps track of the current position in the traversal of the aggregate.
- Aggregate (AbstractCollection)
- 定义一个接口用于创建一个迭代器对象
- ConcreteAggregate (Collection)
- 实现迭代器创建的接口并且返回一个合适的ConcreteIterator实例对象
三、迭代器模式实例代码
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- namespace Iterator_Pattern
- {
- /// <summary>
- /// MainApp startup class for Structural
- /// Iterator Design Pattern.
- /// </summary>
- class MainApp
- {
- /// <summary>
- /// Entry point into console application.
- /// </summary>
- static void Main()
- {
- ConcreteAggregate a = new ConcreteAggregate();
- a[0] = "Item A";
- a[1] = "Item B";
- a[2] = "Item C";
- a[3] = "Item D";
- // Create Iterator and provide aggregate
- ConcreteIterator i = new ConcreteIterator(a);
- Console.WriteLine("Iterating over collection:");
- object item = i.First();
- while (item != null)
- {
- Console.WriteLine(item);
- item = i.Next();
- }
- // Wait for user
- Console.ReadKey();
- }
- }
- /// <summary>
- /// The 'Aggregate' abstract class
- /// </summary>
- abstract class Aggregate
- {
- public abstract Iterator CreateIterator();
- }
- /// <summary>
- /// The 'ConcreteAggregate' class
- /// </summary>
- class ConcreteAggregate : Aggregate
- {
- private ArrayList _items = new ArrayList();
- public override Iterator CreateIterator()
- {
- return new ConcreteIterator(this);
- }
- // Gets item count
- public int Count
- {
- get { return _items.Count; }
- }
- // Indexer
- public object this[int index]
- {
- get { return _items[index]; }
- set { _items.Insert(index, value); }
- }
- }
- /// <summary>
- /// The 'Iterator' abstract class
- /// </summary>
- abstract class Iterator
- {
- public abstract object First();
- public abstract object Next();
- public abstract bool IsDone();
- public abstract object CurrentItem();
- }
- /// <summary>
- /// The 'ConcreteIterator' class
- /// </summary>
- class ConcreteIterator : Iterator
- {
- private ConcreteAggregate _aggregate;
- private int _current = 0;
- // Constructor
- public ConcreteIterator(ConcreteAggregate aggregate)
- {
- this._aggregate = aggregate;
- }
- // Gets first iteration item
- public override object First()
- {
- return _aggregate[0];
- }
- // Gets next iteration item
- public override object Next()
- {
- object ret = null;
- if (_current < _aggregate.Count - 1)
- {
- ret = _aggregate[++_current];
- }
- return ret;
- }
- // Gets current iteration item
- public override object CurrentItem()
- {
- return _aggregate[_current];
- }
- // Gets whether iterations are complete
- public override bool IsDone()
- {
- return _current >= _aggregate.Count;
- }
- }
- }
四、一个使用迭代器模式的例子
该例子借助迭代器模式实现以下操作:迭代访问items的元素并且跳过每个迭代过程中items中指定的数字。
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- namespace Iterator_Pattern
- {
- /// <summary>
- /// MainApp startup class for Real-World
- /// Iterator Design Pattern.
- /// </summary>
- class MainApp
- {
- /// <summary>
- /// Entry point into console application.
- /// </summary>
- static void Main()
- {
- // Build a collection
- Collection collection = new Collection();
- collection[0] = new Item("Item 0");
- collection[1] = new Item("Item 1");
- collection[2] = new Item("Item 2");
- collection[3] = new Item("Item 3");
- collection[4] = new Item("Item 4");
- collection[5] = new Item("Item 5");
- collection[6] = new Item("Item 6");
- collection[7] = new Item("Item 7");
- collection[8] = new Item("Item 8");
- // Create iterator
- Iterator iterator = new Iterator(collection);
- // Skip every other item
- iterator.Step = 2;
- Console.WriteLine("Iterating over collection:");
- for (Item item = iterator.First();
- !iterator.IsDone; item = iterator.Next())
- {
- Console.WriteLine(item.Name);
- }
- // Wait for user
- Console.ReadKey();
- }
- }
- /// <summary>
- /// A collection item
- /// </summary>
- class Item
- {
- private string _name;
- // Constructor
- public Item(string name)
- {
- this._name = name;
- }
- // Gets name
- public string Name
- {
- get { return _name; }
- }
- }
- /// <summary>
- /// The 'Aggregate' interface
- /// </summary>
- interface IAbstractCollection
- {
- Iterator CreateIterator();
- }
- /// <summary>
- /// The 'ConcreteAggregate' class
- /// </summary>
- class Collection : IAbstractCollection
- {
- private ArrayList _items = new ArrayList();
- public Iterator CreateIterator()
- {
- return new Iterator(this);
- }
- // Gets item count
- public int Count
- {
- get { return _items.Count; }
- }
- // Indexer
- public object this[int index]
- {
- get { return _items[index]; }
- set { _items.Add(value); }
- }
- }
- /// <summary>
- /// The 'Iterator' interface
- /// </summary>
- interface IAbstractIterator
- {
- Item First();
- Item Next();
- bool IsDone { get; }
- Item CurrentItem { get; }
- }
- /// <summary>
- /// The 'ConcreteIterator' class
- /// </summary>
- class Iterator : IAbstractIterator
- {
- private Collection _collection;
- private int _current = 0;
- private int _step = 1;
- // Constructor
- public Iterator(Collection collection)
- {
- this._collection = collection;
- }
- // Gets first item
- public Item First()
- {
- _current = 0;
- return _collection[_current] as Item;
- }
- // Gets next item
- public Item Next()
- {
- _current += _step;
- if (!IsDone)
- return _collection[_current] as Item;
- else
- return null;
- }
- // Gets or sets stepsize
- public int Step
- {
- get { return _step; }
- set { _step = value; }
- }
- // Gets current iterator item
- public Item CurrentItem
- {
- get { return _collection[_current] as Item; }
- }
- // Gets whether iteration is complete
- public bool IsDone
- {
- get { return _current >= _collection.Count; }
- }
- }
- }
乐在其中设计模式(C#) - 迭代器模式(Iterator Pattern)
乐在其中设计模式(C#) - 迭代器模式(Iterator Pattern)
作者:webabcd
介绍
提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部表示。
示例
有一个Message实体类,某聚合对象内的各个元素均为该实体对象,现在要提供一种方法顺序地访问这个聚合对象中的各个元素。
MessageModel
using System;
using System.Collections.Generic;
using System.Text;
namespace Pattern.Iterator
{
/// <summary>
/// Message实体类
/// </summary>
public class MessageModel
{
/// <summary>
/// 构造函数
/// </summary>
/// <param name="msg">Message内容</param>
/// <param name="pt">Message发布时间</param>
public MessageModel(string msg, DateTime pt)
{
this._message = msg;
this._publishTime = pt;
}
private string _message;
/// <summary>
/// Message内容
/// </summary>
public string Message
{
get { return _message; }
set { _message = value; }
}
private DateTime _publishTime;
/// <summary>
/// Message发布时间
/// </summary>
public DateTime PublishTime
{
get { return _publishTime; }
set { _publishTime = value; }
}
}
}
ICollection
using System;
using System.Collections.Generic;
using System.Text;
namespace Pattern.Iterator
{
/// <summary>
/// 集合接口(Aggregate)
/// </summary>
public interface ICollection
{
/// <summary>
/// 创建迭代器对象
/// </summary>
/// <returns></returns>
IIterator CreateIterator();
}
}
Collection
using System;
using System.Collections.Generic;
using System.Text;
namespace Pattern.Iterator
{
/// <summary>
/// 集合(ConcreteAggregate)
/// </summary>
public class Collection : ICollection
{
private List<MessageModel> list = new List<MessageModel>();
/// <summary>
/// 创建迭代器对象
/// </summary>
/// <returns></returns>
public IIterator CreateIterator()
{
return new Iterator(this);
}
/// <summary>
/// 集合内的对象总数
/// </summary>
public int Count
{
get { return list.Count; }
}
/// <summary>
/// 索引器
/// </summary>
/// <param name="index">index</param>
/// <returns></returns>
public MessageModel this[int index]
{
get { return list[index]; }
set { list.Add(value); }
}
}
}
IIterator
using System;
using System.Collections.Generic;
using System.Text;
namespace Pattern.Iterator
{
/// <summary>
/// 迭代器接口(IIterator)
/// </summary>
public interface IIterator
{
/// <summary>
/// 第一个对象
/// </summary>
/// <returns></returns>
MessageModel First();
/// <summary>
/// 下一个对象
/// </summary>
/// <returns></returns>
MessageModel Next();
/// <summary>
/// 当前对象
/// </summary>
MessageModel CurrentMessageModel { get; }
/// <summary>
/// 是否迭代完毕
/// </summary>
bool IsDone { get; }
}
}
Iterator
using System;
using System.Collections.Generic;
using System.Text;
namespace Pattern.Iterator
{
/// <summary>
/// 迭代器(Iterator)
/// </summary>
public class Iterator : IIterator
{
private Collection _collection;
private int _current = 0;
private int _step = 1;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="collection"></param>
public Iterator(Collection collection)
{
this._collection = collection;
}
/// <summary>
/// 第一个对象
/// </summary>
/// <returns></returns>
public MessageModel First()
{
_current = 0;
return _collection[_current];
}
/// <summary>
/// 下一个对象
/// </summary>
/// <returns></returns>
public MessageModel Next()
{
_current += _step;
if (!IsDone)
{
return _collection[_current];
}
else
{
return null;
}
}
/// <summary>
/// 当前对象
/// </summary>
public MessageModel CurrentMessageModel
{
get { return _collection[_current]; }
}
/// <summary>
/// 是否迭代完毕
/// </summary>
public bool IsDone
{
get { return _current >= _collection.Count ? true : false; }
}
/// <summary>
/// 步长
/// </summary>
public int Step
{
get { return _step; }
set { _step = value; }
}
}
}
Test
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using I = Pattern.Iterator;
public partial class Iterator : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
I::Collection collection = new I::Collection();
collection[0] = new I::MessageModel("第1条信息", DateTime.Now);
collection[1] = new I::MessageModel("第2条信息", DateTime.Now);
collection[2] = new I::MessageModel("第3条信息", DateTime.Now);
collection[3] = new I::MessageModel("第4条信息", DateTime.Now);
collection[4] = new I::MessageModel("第5条信息", DateTime.Now);
collection[5] = new I::MessageModel("第6条信息", DateTime.Now);
collection[6] = new I::MessageModel("第7条信息", DateTime.Now);
collection[7] = new I::MessageModel("第8条信息", DateTime.Now);
collection[8] = new I::MessageModel("第9条信息", DateTime.Now);
I::Iterator iterator = new I::Iterator(collection);
iterator.Step = 2;
for (I::MessageModel mm = iterator.First(); !iterator.IsDone; mm = iterator.Next())
{
Response.Write(mm.Message);
Response.Write("<br />");
}
}
}
运行结果
第1条信息
第3条信息
第5条信息
第7条信息
第9条信息
参考
http://www.dofactory.com/Patterns/PatternIterator.aspx
OK
[源码下载]