一、迭代器模式简介(Brief Introduction)
迭代器模式(Iterator Pattern),提供一种方法顺序访问一个聚合对象中元素,而不暴露改集合对象的内部表示。
Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
二、解决的问题(What To Solve)
在软件构建过程中,集合对象内部结构常常变化各异。但对于这些集合对象,我们希望在不暴露其内部结构的同时,可以让外部客户代码透明地访问其中包含的元素;同时这种“透明遍历”也为“同一种算法在多种集合对象上进行操作”提供了可能。
当需要访问一个聚集对象,而且不管这些对象是什么都需要遍历的时候,应该考虑用迭代器模式;当需要对聚集有多种方式遍历时,可以考虑使用迭代器模式。其中,你不用关心到底是什么样子的数组作为对象集合,是Array,是List还是简单的数组,迭代器模式会提供给你一个聚合对象的遍历方式,而不用去了解具体是在遍历什么类型的聚合对象。
三、代码:

using System; using System.Collections.Generic; using System.Text; namespace IteratePattern { public class Guest { public string id { get; set; } public string name { get; set; } public Guest(string aId, string aName) { id = aId; name = aName; } } public interface IAggrate { IIterator GetIterator(); } public class ConcreateAggrate:IAggrate { List<object> _guest = new List<object>(); public IIterator GetIterator() { return new ConcreateIterator(this); } public object this[int index] { get{return _guest[index];} set{_guest.Add(value);} } public int count() { return _guest.Count; } } public interface IIterator { bool Next(); } class ConcreateIterator : IIterator { ConcreateAggrate _aggrate; int currentindex; public ConcreateIterator(ConcreateAggrate aAggrate) { _aggrate = aAggrate; currentindex = -1; } public object Current { get { return _aggrate[currentindex]; } } public bool Next() { currentindex++; return _aggrate.count() > currentindex; } } class Program { static void Main(string[] args) { ConcreateAggrate aAggrate = new ConcreateAggrate(); aAggrate[0] = new Guest("1", "hi"); aAggrate[1] = new Guest("2", "my"); aAggrate[2] = new Guest("3", "dear"); aAggrate[3] = new Guest("4", "iterator"); aAggrate[4] = new Guest("5", "pattern"); //ConcreateIterator aIterator = new ConcreateIterator(aAggrate); ConcreateIterator aIterator = (ConcreateIterator)aAggrate.GetIterator(); while (aIterator.Next()) Console.WriteLine(((Guest)aIterator.Current).name); } } }
举例Iterator应用
下面是迭代器所拥有的最小集合,Current是属性,只能Get不能Set。还有两个方法:MoveNext是往下一个元素走,如果访问到最后一个元素之后没有元素了,就返回False;Reset是复位,回到初始位置。
如果有一个容器实现了IEnumerable接口,它就可以支持我们的迭代操作了。这种设计模式已经内化为C#语言的一种元素了,就是Foreach关键字。我们定义的容器首先要实现IEnumerable接口,实现的GetEnumerator方法要返回一个IEnumerator的类型的集合。

using System; using System.Collections.Generic; using System.Text; using System.Collections; namespace IteratePattern { public class Guest { public string id { get; set; } public string name { get; set; } public Guest(string aId, string aName) { id = aId; name = aName; } } public class ConcreateAggrate:IEnumerable { List<object> _guest = new List<object>(); public object this[int index] { get{return _guest[index];} set{_guest.Add(value);} } public int count() { return _guest.Count; } #region IEnumerable 成员 IEnumerator IEnumerable.GetEnumerator() { return new ConcreateIterator(this); } #endregion } class ConcreateIterator : IEnumerator { ConcreateAggrate _aggrate; int currentindex; public ConcreateIterator(ConcreateAggrate aAggrate) { _aggrate = aAggrate; currentindex = -1; } #region IEnumerator 成员 object IEnumerator.Current { get { return _aggrate[currentindex]; } } bool IEnumerator.MoveNext() { currentindex++; return _aggrate.count() > currentindex; } void IEnumerator.Reset() { currentindex = -1; } #endregion } class Program { static void Main(string[] args) { ConcreateAggrate aAggrate = new ConcreateAggrate(); aAggrate[0] = new Guest("1", "hi"); aAggrate[1] = new Guest("2", "my"); aAggrate[2] = new Guest("3", "dear"); aAggrate[3] = new Guest("4", "iterator"); aAggrate[4] = new Guest("5", "pattern"); foreach (Guest aGuest in aAggrate) Console.WriteLine(aGuest.name); } } }
Foreach的工作机制
IEnumerator ietor = aAggrate.GetEnumerator(); while(ietor.MoveNext()) { Guest aGuest = (Guest)ietor.Current; Console.WriteLine(aGuest); }
遍历代码中访问的全部是接口,而不用关心集合的内部结构。上面的代码等同于下面的Foreach。
结构(Structure)
Iterator模式的几个要点
迭代抽象:访问一个聚合对象的内容而无需暴露它的内部表示。迭代多态:为遍历不同的集合结构提供一个统一的接口,从而支持同样的算法在不同的集合结构上进行操作。例如假设我们有一个求和算法
它可以操作在多个支持迭代器的集合上,如果把这个算法写成ArrayList的话,就会非常受限制。同时我们更可以用C#的Foreach语句来写。
我们的算法应该是独立的,写的时候应该尽量操作接口,这样我们写好一个算法,就能应对N种集合的变化,使得同样的算法能在不同的集合上操作。迭代器的健壮性考虑:遍历的同时更改迭代器所在的集合结构,会导致问题。也就是说,我们在迭代的时候,应该只是读取操作,不能更改容器的接口,例如遍历的时候删除一个元素,这样是不可以的。容器的结构师绝对不能碰的,一旦结构更改,遍历就会出问题。
下面这种情况对i进行更改,是不会影响原来的数组内容的,因为i是int类型,它只是一份拷贝。
我们一定要给用户提供尽量纯只读的迭代。保证每个元素被且只被遍历一次。
(引自:山天大畜博客园,http://www.cnblogs.com/cdts_change/archive/2010/10/17/1853689.html)
总结(Conclusion)
从上面的几个示例中就可以看出,尽管我们没有显示的引用迭代器,但实质还是通过迭代器来遍历的。总地来说,迭代器模式就是分离了集合对象的迭代行为,抽象出一个迭代器类来负责,这样既可做到不暴露集合的内部结构,又可以让外部代码可以透明的访问集合内部的元素。
迭代器模式在访问数组、集合、列表等数据时,尤其是数据库数据操作时,是非常普遍的应用,但由于它太普遍了,所以各种高级语言都对他进行了封装,所以反而给人感觉此模式本身不太常用了。
转载请注明出处:Edward_jie,http://www.cnblogs.com/promise-7/archive/2012/05/28/2521918.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· [AI/GPT/综述] AI Agent的设计模式综述