在软件的构建过程中,集合对象(也就是聚集:是一组数据集或者对象集,它可以通过循环来访问 )内部结构常常变化各异。但对于这些集合对象,我们希望在不暴露其内部结构的同时,可以让外部客户代码透明地访问其中包含的元素;同时这种“透明遍历”也 为“同一种算法在多种集合对象上进行操作”提供了可能。使用面向对象技术将这种遍历机制抽象为“迭代器对象”为“应对变化中的集合对象”提供了一种比较好 的方式。
我们在平时的开发中经常直接或间接地使用到此模式,我们使用foreach语句来循环就是在间接的使用C# Iterator迭代器模式。
迭代器就像指针一样可以向前向后移动,在.NET中迭代器只能向后移动。
此模式的UML图如下:
由图可知,它有以下角色
1、Aggregate 接口: 抽象的聚集,通常只留有一个方法让子类去实现,这个方法的作用是获得一个枚举器对象,通常可以起名字为 GetIterator( ),CreateIterator( ) 等等,或者干脆叫做 Iterator( ) 也行。在 C# 中,这个方法的名字叫做 GetEnumerator( ) ,这个我们到后面再讲。当然,在获得枚举器的同时,也要把自己 this(一组数据集)当作参数传给枚举器,想想也是,如果没有数据集,枚举器去枚举什么呢?
2、ConcreteAggregate 类: 具体的聚集,它的实例保存了一组数据集,同时它实现了 Aggregate 接口中唯一的那个方法,通常情况下他也会扩展出一些其他方法便于访问聚集中的数据,常见的有:访问某个位置数据的方法,可以叫做 GetElement(int index) 或者 GetItem(int index) 等等;获得聚集大小的方法,可以起名字为 GetLength( ) 或者 GetSize( ) 等等,全看自己喜好。我们这里叫Count。
3、Iterator 接口: 抽象的枚举器,通常情况下会有三个方法留给子类去实现,他们分别是:Next( ) ,用来把指针移动到聚集中的下一个数据;HasNext( ) ,用来判断是否还有下一个数据;CurrentItem( ),返回当前指针所指位置的数据。也可以把 Next( ) 和 CurrentItem( ) 组成一个方法,在移动指针的同时返回一个数据。也可以有其他的实现方式,或者简单,或者复杂,也是全看个人需求。
4、ConcreteIterator 类:具体的枚举器,它实现了上述的三个方法,通过不同的实现方式,我们可以获得不同的枚举方式,如顺序枚举、倒序枚举等等。当然,这个类的构造方法中会接受一个具体聚集参数,想想也是,如果没有这个数据集,他去枚举什么呢?这个参数就是他要去枚举的对象。
5、被聚集的类,这个可以是任何类,它的许多个对象被存到聚集对象中才能形成一个真正的聚集。
下面,我们用两段代码来示例此模式。
程序如下图:
一、迭代者模式运基本思想示例
1、Aggregate 接口:Aggregate.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyIterator
{
#region 定义Aggregate抽象类
//实现迭代接口,返回迭代器
abstract class Aggregate
{
////在这里进行解藕,将集合对象转换为迭代器
public abstract Iterator CreateIterator();
}
#endregion
}
2、ConcreteAggregate 类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
namespace MyIterator
{
//定义ConcreteAggregate类,它继承自Aggregate
class ConcreteAggregate:Aggregate
{
private ArrayList _items = new ArrayList();
#region 实现基类Aggregate定义的操作CreateIterator
public override Iterator CreateIterator()
{
//因为在ConcreteIterator构造函数中需要传入ConcreteAggregate类的实例
//所以在此处实现CreateIterator功能时ConcreteAggregate类实例作为参数传入
//从而在ConcreteAggregate与CreateIterator之间建立了联系
return new ConcreteIterator(this);
}
#endregion
#region 得到Item的数目
public int Count
{
get { return _items.Count; }
}
#endregion
#region 获取指定位置的元素
public object this[int index]
{
get { return _items[index]; }
set { _items.Insert(index, value); }
}
#endregion
}
}
3、Iterator 接口
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyIterator
{
#region 定义Interator接口
//此处定义了Interator子类需要实现的遍历操作
public abstract class Iterator
{
public abstract object First();
public abstract object Next();
public abstract bool IsDone();
public abstract object CurrentItem();
}
#endregion
}
4、ConcreteIterator 类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyIterator
{
#region 定义ConcreteInterator类
//此类继承自Interator类,实现了迭代器接口
//First(); Next(); IsDone();CurrentItem();
class ConcreteIterator:Iterator
{
private ConcreteAggregate _aggregate;
private int _current = 0;
#region 构造函数
//构造时引入集合实例aggregate,从而将集合类型转换成内部成员
//我们通过ConcreteIterator方法,将集合对象转换为了可迭代对象,这实际上是在对集合对象进行抽象,将他转换为迭代器
public ConcreteIterator(ConcreteAggregate aggregate)
{
this._aggregate = aggregate;
}
#endregion
#region 得到第一个元素
public override object First()
{
return _aggregate[0];
}
#endregion
#region 得到当前元素的下一个元素
public override object Next()
{
object retObject = null;
if( _current<_aggregate.Count-1 )
{
//如果当前项后面还有元素则取得下一个元素并返回
retObject = _aggregate[++_current];
}
return retObject;
}
#endregion
#region 取得当前项元素
public override object CurrentItem()
{
return _aggregate[_current];
}
#endregion
#region 是否遍历完所有元素
public override bool IsDone()
{
return _current >= _aggregate.Count;
}
#endregion
}
#endregion
}
5、被聚集的类,此处我们用字符串来实现
6、客户端应用
#region 运作思想示例
//定义一个集合对象并初始化
ConcreteAggregate ca = new ConcreteAggregate();
for (int i = 0; i < 8; i++)
{
ca[i] = "Item " + (i + 1).ToString();
}
//创建一个迭代器,并传入上面创建的集合对象
ConcreteIterator ci = new ConcreteIterator(ca);
Console.WriteLine("--------------遍历集合对象-----------");
object item = ci.First();
while (item != null)
{
Console.WriteLine(item);
item = ci.Next();
}
Console.ReadKey();
#endregion
二、以士兵作为被聚集的类来示例实现
1、Aggregate 接口:IAbstractCollection接口
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
namespace MyIterator
{
#region IAbstractCollection接口
interface IAbstractCollection
{
SoldierIterator CreateIterator();
}
#endregion
}
2、ConcreteAggregate 类: SoldierCollection类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
namespace MyIterator
{
class SoldierCollection:IAbstractCollection
{
private ArrayList _item = new ArrayList();
//返回迭代器
public SoldierIterator CreateIterator()
{
return new SoldierIterator(this);
}
#region 获取当前集合对象的元素数目
public int Count
{
get { return _item.Count;}
}
#endregion
#region 获取指定位置的元素
public object this[int index]
{
get { return _item[index]; }
set { _item.Add(value); }
}
#endregion
}
}
3、Iterator 接口: IAbstractIterator接口
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyIterator
{
#region
interface IAbstractIterator
{
//要求实现First,Next,IsDone与CurrentItem功能
Soldier First();
Soldier Next();
bool IsDone{get;}
Soldier CurrentItem {get; }
}
#endregion
}
4、ConcreteIterator 类:SoldierIterator类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyIterator
{
class SoldierIterator:IAbstractIterator
{
private SoldierCollection _collection;
private int _current = 0;
private int _step = 1;
#region 构造函数
public SoldierIterator(SoldierCollection collection)
{
this._collection = collection;
}
#endregion
#region 得到队列中的第一名士兵
public Soldier First()
{
_current = 0;
return _collection[_current] as Soldier;
}
#endregion
#region 得到下一名士兵
public Soldier Next()
{
_current += _step;
if (!IsDone)
{
return _collection[_current] as Soldier;
}
else
{
return null;
}
}
#endregion
#region 获取或设置前进步伐
public int Step
{
get { return _step; }
set { _step = value; }
}
#endregion
#region 获取当前士兵
public Soldier CurrentItem
{
get { return _collection[_current] as Soldier; }
}
#endregion
#region 判断是否遍历完成
public bool IsDone
{
get { return _current >= _collection.Count; }
}
#endregion
}
}
5、被聚集的类:Soldier
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyIterator
{
class Soldier
{
#region Name属性
private string _name;
public string Name
{
get { return _name; }
}
#endregion
#region 构造函数
public Soldier(string name)
{
this._name = name;
}
#endregion
}
}
6、客户端应用
#region 我的团长我的团
SoldierCollection collection = new SoldierCollection();
collection[0] = new Soldier("孟烦了");
collection[1] = new Soldier("不辣");
collection[2] = new Soldier("迷龙");
collection[3] = new Soldier("豆饼");
collection[4] = new Soldier("要麻");
collection[5] = new Soldier("蛇屁股");
collection[6] = new Soldier("康丫");
collection[7] = new Soldier("郝兽医");
collection[8] = new Soldier("阿译");
SoldierIterator si = new SoldierIterator(collection);
//设置指针前移距离
si.Step = 1;
//按指定步距遍历一次
Console.WriteLine("--------我的团长我的团----------");
//Soldier sd = si.First();
//while(sd!=null)
//{
// Console.WriteLine(sd.Name);
// sd=si.Next();
//}
for (Soldier sd = si.First(); !si.IsDone; sd = si.Next())
{
Console.WriteLine(sd.Name);
}
Console.ReadKey();
#endregion
运行效果如下: