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)

定义遍历的通用方法:

csharp 复制代码
// 抽象迭代器接口
public interface IBookIterator
{
    bool HasNext(); // 判断是否有下一个元素
    Book Next();    // 获取下一个元素
}

2、抽象聚合(IAggregate)

定义创建迭代器的方法:

csharp 复制代码
// 抽象聚合接口
public interface IBookAggregate
{
    void AddBook(Book book);       // 添加图书
    IBookIterator CreateIterator(); // 创建迭代器
}

3、聚合元素(Book)

聚合中存储的具体元素:

csharp 复制代码
// 图书类(聚合中的元素)
public class Book
{
    public string Name { get; }    // 书名
    public string Author { get; }  // 作者

    public Book(string name, string author)
    {
        Name = name;
        Author = author;
    }
}

4、具体聚合与迭代器

4.1、书架(数组实现)
csharp 复制代码
// 具体聚合:书架(数组存储)
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;
        else
            throw 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、电子书库(链表实现)
csharp 复制代码
// 具体聚合:电子书库(链表存储)
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、客户端调用

csharp 复制代码
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}");
        }
    }
}

输出结果

csharp 复制代码
=== 遍历书架 ===
书名:《设计模式》,作者:Erich Gamma
书名:《C#编程指南》,作者:微软
书名:《算法导论》,作者:Thomas H. Cormen

=== 遍历电子书库 ===
书名:《深入理解C#》,作者:Jon Skeet
书名:《.NET框架设计》,作者:Jeffrey Richter

迭代器模式通过封装遍历逻辑,让客户端可以忽略聚合的内部细节,是框架设计中简化集合操作的核心模式。

相关推荐
笨手笨脚の8 小时前
设计模式-命令模式
设计模式·命令模式·行为型设计模式
adair-zhang8 小时前
23种设计模式
设计模式
十五年专注C++开发8 小时前
QT 中的元对象系统(六):connect函数详解
开发语言·c++·qt·设计模式·系统架构·qevent
Deschen9 小时前
设计模式-适配器模式
java·设计模式·适配器模式
junehn9 小时前
深入解析MySQL索引底层原理B+树与性能优化实战
迭代器模式
Asort12 小时前
JavaScript设计模式(十一):享元模式(Flyweight) - 优化内存与性能的利器
前端·javascript·设计模式
Asort12 小时前
JavaScript设计模式(十)——外观模式 (Facade)
前端·javascript·设计模式
余辉zmh13 小时前
【C++篇】:LogStorm——基于多设计模式下的同步&异步高性能日志库项目
开发语言·c++·设计模式
王嘉俊92514 小时前
设计模式--装饰器模式:动态扩展对象功能的优雅设计
java·设计模式·装饰器模式