设计模式学习总结-迭代器模式(Iterator Pattern)
问题:
在面向对象的软件设计中,经常会遇到一些聚集对象,按一定的顺序的遍历访问问题,这个遍历算法究竟应该由谁来实现呢,聚集对象本身?这样聚集对象承受了过多的功能,不仅要维护聚集对象内的元素,还要提供遍历自身的接口,而且由于遍历状态保存的问题,不能对同一个容器对象同时进行多个遍历,这不符合单一职责原则。如果将遍历算法交给客户端,会将容器的内部细节暴露无遗,而且客户端与聚集对象高度耦合。分离了集合对象的遍历行为,将遍历算法交给这个迭代器角色来完成,可以很好的避免容器内部细节的暴露,而且也使得设计符合“单一职责原则”,另外迭代器模式抽象了具体迭代器角色,可以通过对一个抽象迭代器多个集成可来完成同一聚集对象的多种遍历。
定义:
迭代器(Iterator)模式,又叫做游标(Cursor)模式。
提供一种方法顺序访问一个聚合对象(或容器对象:container)中各个元素, 而又不需暴露该对象的内部表示。
意图:
分离了集合对象的遍历行为,将遍历算法交给这个迭代器角色来完成,可以很好的避免容器内部细节的暴露,而且也使得设计符合“单一职责原则”,另外迭代器模式抽象了具体迭代器角色,可以通过对一个抽象迭代器多个集成可来完成同一聚集对象的多种遍历。
参与者:
•迭代器角色(Iterator):
定义访问和遍历元素的接口。
•具体迭代器角色(Concrete Iterator):
关联到被迭代的具体聚集对象角色,继承迭代器角色实现具体的迭代,并负责管理记录遍历中的当前位置。
•聚集对象抽象角色(Aggregate):
责提供创建具体迭代器角色的接口。
•具体聚集对象角色(Concrete Aggreate):
持有一个对象的集合,实现创建具体迭代器角色的接口,返回集合遍历所依赖的一个迭代器。
UML图:
实例说明:
诺基亚手机工厂
诺基亚返修仓库遍历返修手机
uml图如下:
代码:
/// 返修手机对象
/// </summary>
public class ReworkPhone
{
/// <summary>
/// 手机名称
/// </summary>
public string PhoneName { get; set; }
/// <summary>
/// 生产日期
/// </summary>
public string ProductionDate { get; set; }
/// <summary>
/// 返厂日期
/// </summary>
public string ReworkDate { get; set; }
}
/// <summary>
/// 聚集对象抽象角色(Aggregate)供创建具体迭代器角色的接口。
/// </summary>
public interface IReworkPhoneContainer
{
IReworkIterator GetIterator();
}
/// <summary>
/// 定义访问和遍历元素的接口
/// </summary>
public interface IReworkIterator
{
bool HasNext();
void First();
void Next();
Object CurrentItem();
}
/// <summary>
/// 返修手机仓库(具体聚集对象角色)
/// </summary>
public class ReworkPhoneContainer : IReworkPhoneContainer
{
List<ReworkPhone> ReworkPhoneList = null;
public ReworkPhoneContainer()
{
ReworkPhoneList = new List<ReworkPhone>();
}
public IReworkIterator GetIterator()
{
return new ReworkConcreteIterator(this);
}
public void Add(ReworkPhone phone)
{
ReworkPhoneList.Add(phone);
}
public object GetItemByIndex(int index)
{
return ReworkPhoneList[index];
}
public int Count
{
get { return ReworkPhoneList.Count; }
}
}
/// <summary>
/// 返修仓库 中返修手机迭代的具体实现 (具体迭代器角色)以怎样的方式顺序遍历元素
/// </summary>
public class ReworkConcreteIterator : IReworkIterator
{
private ReworkPhoneContainer list;
private int index;
public ReworkConcreteIterator(ReworkPhoneContainer list)
{
this.list = list;
index = 0;
}
public bool HasNext()
{
return index < list.Count;
}
public void First()
{
index = 0;
}
public void Next()
{
if (index < list.Count)
{
index++;
}
}
public object CurrentItem()
{
return list.GetItemByIndex(index);
}
}
void IteratorTest()
{
ReworkPhoneContainer PhoneContainer = new ReworkPhoneContainer();
PhoneContainer.Add(new ReworkPhone() { PhoneName = "N8", ProductionDate = "2011-6-27 6:00:46", ReworkDate = "2012-1-27 6:40:01" });
PhoneContainer.Add(new ReworkPhone() { PhoneName = "N9", ProductionDate = "2011-1-27 9:44:46", ReworkDate = "2012-2-27 8:45:09" });
PhoneContainer.Add(new ReworkPhone() { PhoneName = "N9", ProductionDate = "2011-4-27 14:44:46", ReworkDate = "2012-3-27 14:05:00" });
PhoneContainer.Add(new ReworkPhone() { PhoneName = "N8", ProductionDate = "2012-7-27 16:44:46", ReworkDate = "2012-4-27 16:45:01" });
IReworkIterator iterator = new ReworkConcreteIterator(PhoneContainer);
while (iterator.HasNext())
{
ReworkPhone item = iterator.CurrentItem() as ReworkPhone;
System.Console.WriteLine("{0}送修的{1},返修完成!", item.ReworkDate, item.PhoneName);
iterator.Next();
}
System.Console.WriteLine("所有手机返修完成!");
System.Console.Read();
}
.NET中的Iterator模式
.NET下已提供了一个迭代器的角色(IEnumerator)与聚集接口(IEnumerable),并在.Net集合类中有大量Iterator模式的实现
/// 返修手机对象
/// </summary>
public class ReworkPhone
{
/// <summary>
/// 手机名称
/// </summary>
public string PhoneName { get; set; }
/// <summary>
/// 生产日期
/// </summary>
public string ProductionDate { get; set; }
/// <summary>
/// 返厂日期
/// </summary>
public string ReworkDate { get; set; }
}
/// <summary>
/// 返修手机仓库(具体聚集对象角色)
/// </summary>
public class ReworkPhoneContainer : IEnumerable
{
List<ReworkPhone> ReworkPhoneList = null;
public ReworkPhoneContainer()
{
ReworkPhoneList = new List<ReworkPhone>();
}
public void Add(ReworkPhone phone)
{
ReworkPhoneList.Add(phone);
}
public object GetItemByIndex(int index)
{
return ReworkPhoneList[index];
}
public int Count
{
get { return ReworkPhoneList.Count; }
}
public IEnumerator GetEnumerator()
{
return new ReworkConcreteIterator(this);
}
}
/// <summary>
/// 返修仓库 中返修手机迭代的具体实现 (具体迭代器角色)以怎样的方式顺序遍历元素
/// </summary>
public class ReworkConcreteIterator : IEnumerator
{
private ReworkPhoneContainer list;
private int index;
public ReworkConcreteIterator(ReworkPhoneContainer list)
{
this.list = list;
index = 0;
}
public void Reset()
{
index = 0;
}
public bool MoveNext()
{
if (index < list.Count-1)
{
index++;
return true;
}
return false;
}
public object Current
{
get
{
return list.GetItemByIndex(index);
}
}
}
/// <summary>
/// 客户端测试
/// </summary>
public void IteratorTest()
{
ReworkPhoneContainer PhoneContainer = new ReworkPhoneContainer();
PhoneContainer.Add(new ReworkPhone() { PhoneName = "N8", ProductionDate = "2011-6-27 6:00:46", ReworkDate = "2012-1-27 6:40:01" });
PhoneContainer.Add(new ReworkPhone() { PhoneName = "N9", ProductionDate = "2011-1-27 9:44:46", ReworkDate = "2012-2-27 8:45:09" });
PhoneContainer.Add(new ReworkPhone() { PhoneName = "N9", ProductionDate = "2011-4-27 14:44:46", ReworkDate = "2012-3-27 14:05:00" });
PhoneContainer.Add(new ReworkPhone() { PhoneName = "N8", ProductionDate = "2012-7-27 16:44:46", ReworkDate = "2012-4-27 16:45:01" });
IEnumerator iterator = new ReworkConcreteIterator(PhoneContainer);
do
{
ReworkPhone item = iterator.Current as ReworkPhone;
System.Console.WriteLine("{0}送修的{1},返修完成!", item.ReworkDate, item.PhoneName);
}
while (iterator.MoveNext());
System.Console.WriteLine("所有手机返修完成!");
System.Console.Read();
}
.NET2.0 下提供了yield return,可以在实现利聚集接口(IEnumerable)接口 IEnumerator GetEnumerator() 方法上 实现一个简单的迭代
/// 返修手机对象
/// </summary>
public class ReworkPhone
{
/// <summary>
/// 手机名称
/// </summary>
public string PhoneName { get; set; }
/// <summary>
/// 生产日期
/// </summary>
public string ProductionDate { get; set; }
/// <summary>
/// 返厂日期
/// </summary>
public string ReworkDate { get; set; }
}
/// <summary>
/// 返修手机仓库(具体聚集对象角色)
/// </summary>
public class ReworkPhoneContainer : IEnumerable
{
List<ReworkPhone> ReworkPhoneList = null;
public ReworkPhoneContainer()
{
ReworkPhoneList = new List<ReworkPhone>();
}
public void Add(ReworkPhone phone)
{
ReworkPhoneList.Add(phone);
}
public object GetItemByIndex(int index)
{
return ReworkPhoneList[index];
}
public int Count
{
get { return ReworkPhoneList.Count; }
}
public IEnumerator GetEnumerator()
{
foreach (var item in ReworkPhoneList)
{
yield return item;
}
}
}
/// <summary>
/// 客户端测试
/// </summary>
public void IteratorTest()
{
ReworkPhoneContainer PhoneContainer = new ReworkPhoneContainer();
PhoneContainer.Add(new ReworkPhone() { PhoneName = "N8", ProductionDate = "2011-6-27 6:00:46", ReworkDate = "2012-1-27 6:40:01" });
PhoneContainer.Add(new ReworkPhone() { PhoneName = "N9", ProductionDate = "2011-1-27 9:44:46", ReworkDate = "2012-2-27 8:45:09" });
PhoneContainer.Add(new ReworkPhone() { PhoneName = "N9", ProductionDate = "2011-4-27 14:44:46", ReworkDate = "2012-3-27 14:05:00" });
PhoneContainer.Add(new ReworkPhone() { PhoneName = "N8", ProductionDate = "2012-7-27 16:44:46", ReworkDate = "2012-4-27 16:45:01" });
foreach (var obj in PhoneContainer)
{
ReworkPhone item = obj as ReworkPhone;
System.Console.WriteLine("{0}送修的{1},返修完成!", item.ReworkDate, item.PhoneName);
}
System.Console.WriteLine("所有手机返修完成!");
System.Console.Read();
}
优点:
•支持以不同的方式遍历一个集合对象。根据实现方式的不同,效果上会有差别。
•简化了集合对象的接口。聚集对象不负责提供遍历算法。
•对同一个容器对象,可以同时进行多个遍历。因为遍历状态是保存在每一个迭代器对象中的。
缺点:
•增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。。
•集合类与迭代器类非常紧密地关联在一起。
应用情景:
•访问一个容器对象的内容而无需暴露它的内部表示。
•支持对容器对象的多种遍历。
•为遍历不同的容器结构提供一个统一的接口。