109、23种设计模式之迭代器模式(18/23)
一、定义
迭代器模式是一种行为型设计模式,它提供一种统一的方式遍历聚合对象(如集合、列表、树等)中的元素,同时不暴露聚合对象的内部实现细节。其核心是将 “遍历逻辑” 与 “聚合对象” 解耦,使客户端能以一致的代码操作不同类型的聚合,无需关心聚合的底层数据结构(如数组、链表、哈希表等)。
二、优缺点分析
优点
1、解耦遍历与聚合:客户端无需了解聚合的内部结构(如数组用索引、链表用指针),只需通过迭代器的通用方法遍历,降低代码耦合度。
2、统一遍历接口:不同聚合的遍历逻辑被封装在各自的迭代器中,客户端可通过相同代码操作不同聚合(如用同一方法遍历数组和链表)。
3、符合开闭原则:新增聚合类型时,只需实现对应的迭代器,无需修改现有客户端代码;也可新增迭代器实现多种遍历方式(如正序、逆序)。
4、单一职责原则:聚合仅负责存储数据,遍历逻辑交给迭代器,职责更清晰。
缺点
1、类数量增加:每种聚合通常需要对应一个迭代器,可能导致系统中类的数量增多。
2、遍历效率损耗:对简单聚合(如数组),直接通过索引遍历可能比迭代器更高效(但灵活性通常能弥补这一差异)。
3、迭代中修改聚合的风险:若遍历过程中增删聚合元素,可能导致迭代器状态混乱(需额外处理,如 C# 的InvalidOperationException)。
三、应用场景
1、需要统一遍历不同聚合:当系统中有多种聚合类型(如数组、链表、字典),且希望用相同代码遍历它们时(如框架中的集合类)。
2、不希望暴露聚合内部结构:当聚合的实现复杂(如树、图),需隐藏内部细节(如数据库查询结果集的遍历)。
3、需要多种遍历方式:同一聚合需支持正序、逆序、过滤等多种遍历逻辑(如双向迭代器、条件迭代器)。
4、框架或工具类开发:开发通用组件(如集合库、ORM 框架)时,迭代器是核心组件(如 C# 的IEnumerator)。
四、关键点总结
1、核心思想:将遍历逻辑从聚合中分离,通过迭代器封装遍历细节,实现 “遍历与聚合” 的解耦。
2、核心角色:
- 抽象迭代器(如IIterator):定义遍历接口(HasNext、Next)。
- 具体迭代器(如BookshelfIterator):实现具体聚合的遍历逻辑。
- 抽象聚合(如IAggregate):定义创建迭代器的方法。
- 具体聚合(如Bookshelf):存储元素并返回对应迭代器。
3、C# 特性:.NET 框架的IEnumerator和IEnumerable接口是迭代器模式的典型实现,foreach循环底层依赖这两个接口,简化了迭代器的使用。
4、设计原则:符合开闭原则(新增聚合 / 迭代器无需修改客户端)和单一职责原则(聚合与迭代器各司其职)。
五、C# 代码示例
以 “遍历两种图书集合(书架、电子书库)” 为例,演示迭代器模式的实现。
1、抽象迭代器(IIterator)
定义遍历的通用方法:
// 抽象迭代器接口
public interface IBookIterator
{bool HasNext(); // 判断是否有下一个元素Book Next(); // 获取下一个元素
}
2、抽象聚合(IAggregate)
定义创建迭代器的方法:
// 抽象聚合接口
public interface IBookAggregate
{void AddBook(Book book); // 添加图书IBookIterator CreateIterator(); // 创建迭代器
}
3、聚合元素(Book)
聚合中存储的具体元素:
// 图书类(聚合中的元素)
public class Book
{public string Name { get; } // 书名public string Author { get; } // 作者public Book(string name, string author){Name = name;Author = author;}
}
4、具体聚合与迭代器
4.1、书架(数组实现)
// 具体聚合:书架(数组存储)
public class Bookshelf : IBookAggregate
{private Book[] _books; // 数组存储图书private int _count; // 当前图书数量public Bookshelf(int capacity){_books = new Book[capacity];_count = 0;}public void AddBook(Book book){if (_count < _books.Length)_books[_count++] = book;elsethrow new InvalidOperationException("书架已满");}// 返回书架的迭代器public IBookIterator CreateIterator(){return new BookshelfIterator(this);}// 供迭代器访问内部元素的方法(隐藏数组细节)internal Book GetBookAt(int index) => _books[index];internal int GetCount() => _count;// 具体迭代器:适配数组遍历private class BookshelfIterator : IBookIterator{private readonly Bookshelf _bookshelf;private int _currentIndex; // 当前索引public BookshelfIterator(Bookshelf bookshelf){_bookshelf = bookshelf;_currentIndex = 0; // 从0开始}public bool HasNext() => _currentIndex < _bookshelf.GetCount();public Book Next(){if (!HasNext())throw new InvalidOperationException("没有更多图书");return _bookshelf.GetBookAt(_currentIndex++);}}
}
4.2、电子书库(链表实现)
// 具体聚合:电子书库(链表存储)
public class EBookLibrary : IBookAggregate
{// 链表节点private class Node{public Book Book { get; }public Node Next { get; set; }public Node(Book book){Book = book;Next = null;}}private Node _head; // 头节点private int _count; // 图书数量public EBookLibrary(){_head = null;_count = 0;}public void AddBook(Book book){Node newNode = new Node(book);if (_head == null)_head = newNode;else{Node current = _head;while (current.Next != null)current = current.Next;current.Next = newNode;}_count++;}// 返回电子书库的迭代器public IBookIterator CreateIterator(){return new EBookLibraryIterator(this);}// 供迭代器访问头节点internal Node GetHead() => _head;// 具体迭代器:适配链表遍历private class EBookLibraryIterator : IBookIterator{private readonly EBookLibrary _library;private Node _currentNode; // 当前节点public EBookLibraryIterator(EBookLibrary library){_library = library;_currentNode = _library.GetHead(); // 从头节点开始}public bool HasNext() => _currentNode != null;public Book Next(){if (!HasNext())throw new InvalidOperationException("没有更多电子书");Book book = _currentNode.Book;_currentNode = _currentNode.Next; // 移动到下一个节点return book;}}
}
5、客户端调用
class Client
{static void Main(string[] args){// 1. 书架(数组实现)IBookAggregate bookshelf = new Bookshelf(3);bookshelf.AddBook(new Book("《设计模式》", "Erich Gamma"));bookshelf.AddBook(new Book("《C#编程指南》", "微软"));bookshelf.AddBook(new Book("《算法导论》", "Thomas H. Cormen"));// 2. 电子书库(链表实现)IBookAggregate ebookLib = new EBookLibrary();ebookLib.AddBook(new Book("《深入理解C#》", "Jon Skeet"));ebookLib.AddBook(new Book("《.NET框架设计》", "Jeffrey Richter"));// 3. 统一遍历Console.WriteLine("=== 遍历书架 ===");TraverseBooks(bookshelf);Console.WriteLine("\n=== 遍历电子书库 ===");TraverseBooks(ebookLib);}// 通用遍历方法(依赖抽象,不依赖具体实现)static void TraverseBooks(IBookAggregate aggregate){IBookIterator iterator = aggregate.CreateIterator();while (iterator.HasNext()){Book book = iterator.Next();Console.WriteLine($"书名:{book.Name},作者:{book.Author}");}}
}
输出结果
=== 遍历书架 ===
书名:《设计模式》,作者:Erich Gamma
书名:《C#编程指南》,作者:微软
书名:《算法导论》,作者:Thomas H. Cormen=== 遍历电子书库 ===
书名:《深入理解C#》,作者:Jon Skeet
书名:《.NET框架设计》,作者:Jeffrey Richter
迭代器模式通过封装遍历逻辑,让客户端可以忽略聚合的内部细节,是框架设计中简化集合操作的核心模式。