迭代器模式
迭代器模式(Iterator Pattern)
模式定义
迭代器模式是一种行为型设计模式,它提供一种方法顺序访问一个聚合对象中的各个元素,而无需暴露该对象的内部表示。
核心思想
- 封装遍历逻辑:将集合的遍历行为抽象为独立的迭代器对象,避免暴露集合内部结构。
- 职责分离:集合负责管理元素,迭代器负责遍历元素,符合单一职责原则。
- 统一接口:为不同的集合提供一致的遍历方式(如数组、链表、树等)。
模式结构
迭代器模式包含以下核心角色:
| 角色 | 描述 |
|---|---|
| IIterator |
迭代器接口,定义遍历方法(如 MoveNext, Current)。 |
| IAggregate |
聚合接口,定义创建迭代器的方法(如 GetIterator)。 |
| ConcreteAggregate | 具体聚合类,实现聚合接口,存储数据(如 BookCollection)。 |
| ConcreteIterator | 具体迭代器,实现迭代器接口,封装遍历逻辑(如 BookIterator)。 |
代码示例
1. 定义迭代器与聚合接口
// 迭代器接口
public interface IIterator<T>
{
bool MoveNext();
T Current { get; }
}
// 聚合接口
public interface IAggregate<T>
{
IIterator<T> GetIterator();
}
2. 实现具体聚合类(书籍集合)
public class BookCollection : IAggregate<Book>
{
private List<Book> _books = new List<Book>();
public void Add(Book book) => _books.Add(book);
// 返回具体迭代器
public IIterator<Book> GetIterator() => new BookIterator(_books);
}
public class Book
{
public string Title { get; set; }
public string Author { get; set; }
}
3. 实现具体迭代器
public class BookIterator : IIterator<Book>
{
private readonly List<Book> _books;
private int _position = -1;
public BookIterator(List<Book> books) => _books = books;
public bool MoveNext()
{
return _books.Count> ++_position;
}
public Book Current => (_position >= 0 && _position < _books.Count)
? _books[_position]
: throw new InvalidOperationException();
}
4. 使用迭代器遍历集合
var collection = new BookCollection();
collection.Add(new Book { Title = "Design Patterns", Author ="F" });
collection.Add(new Book { Title = "Clean Code", Author = "Robert C. Martin" });
IIterator<Book> iterator = collection.GetIterator();
while (iterator.MoveNext())
{
Console.WriteLine($"Book: {iterator.Current.Title}, Author: {iterator.Current.Author}");
}
代码分析
1.接口分离
- IIterator 和 IAggregate 接口确保遍历逻辑与集合解耦。
- 客户端仅依赖接口,不关心具体集合类型(如 List
或 T[])。
2.遍历控制
- MoveNext() 移动游标并返回是否存在下一个元素。
- Current 属性验证当前游标位置,避免越界访问。
3.扩展性
- 新增遍历方式(如逆序遍历)只需实现新的 ConcreteIterator,无需修改集合代码。
高级应用场景与扩展
1. 支持多种遍历策略
为同一集合提供不同遍历方式(如顺序、逆序、条件过滤),通过不同迭代器实现。
示例:逆序迭代器
public class ReverseBookIterator : IIterator<Book>
{
private readonly List<Book> _books;
private int _position;
public ReverseBookIterator(List<Book> books)
{
_books = books;
_position = _books.Count; // 从末尾开始
}
public bool MoveNext()
{
_position--;
return _position >= 0;
}
public Book Current => (_position >= 0 && _position < _books.Count)
? _books[_position]
: throw new InvalidOperationException();
}
使用方式
// 聚合类中新增逆序迭代器方法
public IIterator<Book> GetReverseIterator() => new ReverseBookIterator(_books);
2. 惰性加载与 yield return
利用 C# 的 yield return 实现按需加载数据,减少内存占用。
示例:分页加载数据
public class PagedBookCollection : IEnumerable<Book>
{
private readonly int _pageSize;
private readonly List<Book> _allBooks;
public PagedBookCollection(List<Book> books, int pageSize = 5)
{
_allBooks = books;
_pageSize = pageSize;
}
public IEnumerator<Book> GetEnumerator()
{
int currentPage = 0;
while (true)
{
// 模拟分页加载(实际可能从数据库加载)
var page = _allBooks.Skip(currentPage * _pageSize).Take(_pageSize).ToList();
if (page.Count == 0) yield break;
foreach (var book in page)
{
yield return book;
}
currentPage++;
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
3. 组合模式与树形结构遍历
迭代器模式常与组合模式结合,遍历树形结构(如文件系统、菜单树)。
示例:树节点遍历
public class TreeNode
{
public string Name { get; set; }
public List<TreeNode> Children { get; } = new List<TreeNode>();
}
// 深度优先迭代器
public class DepthFirstIterator : IIterator<TreeNode>
{
private Stack<TreeNode> _stack = new Stack<TreeNode>();
public DepthFirstIterator(TreeNode root)
{
_stack.Push(root);
}
public bool MoveNext()
{
if (_stack.Count == 0) return false;
var current = _stack.Pop();
foreach (var child in current.Children.Reverse())
{
_stack.Push(child);
}
return true;
}
public TreeNode Current => _stack.Peek();
}
C# 迭代器的底层机制
1. IEnumerable 与 IEnumerator
- IEnumerable
:声明集合可被遍历(通过 GetEnumerator 方法)。 - IEnumerator
:提供遍历的游标控制(MoveNext、Current、Reset)。
2. 编译器生成的状态机
使用 yield return 时,编译器会自动生成一个状态机类,保存当前迭代位置和局部变量。
反编译后的 yield 代码
// 编译器生成的代码(简化)
public class GeneratedEnumerator : IEnumerator<Book>
{
private int _state;
private Book _current;
private List<Book> _books;
private int _index;
public Book Current => _current;
public bool MoveNext()
{
switch (_state)
{
case 0:
_index = 0;
_state = 1;
goto case 1;
case 1:
if (_index < _books.Count)
{
_current = _books[_index];
_index++;
_state = 1;
return true;
}
_state = -1;
return false;
default:
return false;
}
}
}
迭代器模式的常见问题
1. 线程安全问题
- 问题:多个线程同时遍历同一集合可能导致状态冲突。
- 解决方案:为每个线程创建独立的迭代器实例。
2. 遍历过程中的集合修改
- 问题:在遍历时修改集合(如增删元素)可能导致异常(。
- 解决方案:实现集合版本号检查(如 List
的 _version 字段)。

浙公网安备 33010602011771号