设计模式(十七)行为型:迭代器模式详解

发布于:2025-07-29 ⋅ 阅读:(12) ⋅ 点赞:(0)

设计模式(十七)行为型:迭代器模式详解

迭代器模式(Iterator Pattern)是 GoF 23 种设计模式中的行为型模式之一,其核心价值在于提供一种统一的方式遍历聚合对象(如集合、容器)中的元素,而无需暴露其内部表示结构。它将遍历算法从聚合对象中分离出来,封装在独立的迭代器对象中,实现了“单一职责原则”和“开闭原则”。迭代器模式是现代编程语言集合框架的基石,广泛应用于各种数据结构(列表、树、图、哈希表)的遍历操作,是实现 for-each 循环、流式处理(Stream)、延迟计算、外部迭代等机制的核心支撑,是构建可复用、可扩展、高内聚低耦合系统的必备设计模式。

一、详细介绍

迭代器模式解决的是“客户端需要访问聚合对象中的所有元素,但又不希望依赖其内部实现细节”的问题。在传统设计中,聚合类(如 ListTree)通常提供 get(i)elements() 等方法让客户端直接访问内部数据,这导致:

  • 客户端代码与聚合的内部结构(数组、链表、树)紧耦合;
  • 聚合类职责过重,既管理数据又提供遍历逻辑;
  • 难以支持多种遍历方式(如正序、逆序、深度优先、广度优先);
  • 并发修改时难以保证遍历的安全性。

迭代器模式通过引入一个独立的迭代器对象(Iterator) 来封装遍历过程。客户端通过迭代器提供的统一接口(如 hasNext()next())访问元素,而无需关心底层是数组、链表还是树。聚合对象(Aggregate)负责创建并返回一个合适的迭代器实例。

该模式包含以下核心角色:

  • Iterator(迭代器接口):定义遍历聚合对象所需的操作,通常包括:
    • hasNext():判断是否还有下一个元素。
    • next():返回当前元素并将游标移至下一个。
    • remove()(可选):移除当前元素(Java 中常见)。
  • ConcreteIterator(具体迭代器):实现 Iterator 接口,针对特定聚合结构(如数组、链表)实现具体的遍历逻辑。它持有对聚合对象的引用或内部状态(如索引、当前节点)。
  • Aggregate(聚合接口):定义创建迭代器的方法,通常为 createIterator()
  • ConcreteAggregate(具体聚合类):实现 Aggregate 接口,返回一个与自身结构匹配的 ConcreteIterator 实例。
  • Client(客户端):通过聚合对象获取迭代器,并使用迭代器接口遍历元素。

迭代器模式的关键优势:

  • 解耦聚合与遍历:客户端不依赖聚合的内部结构。
  • 支持多种遍历方式:同一聚合可提供多种迭代器(如正序、逆序、过滤迭代器)。
  • 简化客户端代码:提供统一的遍历接口。
  • 支持并发安全遍历:迭代器可实现“快照”或“失败快速”机制(如 Java 的 ConcurrentModificationException)。
  • 支持延迟计算(Lazy Evaluation):元素可在 next() 调用时动态生成(如数据库游标、无限序列)。

与“访问者模式”相比,迭代器关注线性访问元素,访问者关注在不修改类的前提下为对象结构添加新操作;与“生成器模式”相比,生成器用于创建复杂对象,迭代器用于访问已有对象集合

迭代器可分为:

  • 外部迭代器(External Iterator):客户端主动控制遍历过程(如 while(it.hasNext()))。
  • 内部迭代器(Internal Iterator):由聚合或迭代器内部控制遍历,客户端提供回调(如 Java 8 的 forEach(Consumer)),更接近“函数式编程”。

二、迭代器模式的UML表示

以下是迭代器模式的标准 UML 类图:

implements
implements
has a
gets iterator
uses for traversal
«interface»
Iterator
+hasNext()
+next()
+remove()
ConcreteIterator
-aggregate: ConcreteAggregate
-currentIndex: int
+hasNext()
+next()
+remove()
«interface»
Aggregate
+createIterator()
ConcreteAggregate
-items: List<Object>
+createIterator()
Client
+main(args: String[])

图解说明

  • Iterator 定义统一遍历接口。
  • ConcreteIterator 针对 ConcreteAggregate 实现具体遍历逻辑。
  • ConcreteAggregate 实现 createIterator() 返回其对应的迭代器。
  • Client 通过聚合获取迭代器并遍历。

三、一个简单的Java程序实例及其UML图

以下是一个自定义的 BookShelf 聚合类,使用迭代器模式遍历书架上的书籍。

Java 程序实例
import java.util.ArrayList;
import java.util.List;

// 书籍类
class Book {
    private String title;
    private String author;

    public Book(String title, String author) {
        this.title = title;
        this.author = author;
    }

    // Getter 方法
    public String getTitle() { return title; }
    public String getAuthor() { return author; }

    @Override
    public String toString() {
        return "\"" + title + "\" by " + author;
    }
}

// 迭代器接口
interface Iterator<T> {
    boolean hasNext();
    T next();
}

// 聚合接口
interface Aggregate<T> {
    Iterator<T> createIterator();
}

// 具体聚合类:书架
class BookShelf implements Aggregate<Book> {
    private List<Book> books = new ArrayList<>();

    public void addBook(Book book) {
        books.add(book);
    }

    public int getSize() {
        return books.size();
    }

    public Book getBookAt(int index) {
        return books.get(index);
    }

    // 实现创建迭代器
    @Override
    public Iterator<Book> createIterator() {
        return new BookShelfIterator(this);
    }
}

// 具体迭代器:书架迭代器
class BookShelfIterator implements Iterator<Book> {
    private BookShelf bookShelf;
    private int currentIndex = 0;

    public BookShelfIterator(BookShelf bookShelf) {
        this.bookShelf = bookShelf;
    }

    @Override
    public boolean hasNext() {
        return currentIndex < bookShelf.getSize();
    }

    @Override
    public Book next() {
        if (!hasNext()) {
            throw new java.util.NoSuchElementException();
        }
        Book book = bookShelf.getBookAt(currentIndex);
        currentIndex++;
        return book;
    }
}

// 客户端使用示例
public class IteratorPatternDemo {
    public static void main(String[] args) {
        System.out.println("📚 书架管理系统 - 迭代器模式示例\n");

        // 创建书架并添加书籍
        BookShelf bookShelf = new BookShelf();
        bookShelf.addBook(new Book("设计模式", "GoF"));
        bookShelf.addBook(new Book("重构", "Martin Fowler"));
        bookShelf.addBook(new Book("代码大全", "Steve McConnell"));

        // 获取迭代器
        Iterator<Book> iterator = bookShelf.createIterator();

        System.out.println("📖 正在遍历书架中的书籍:");
        while (iterator.hasNext()) {
            Book book = iterator.next();
            System.out.println("  ➡️ " + book);
        }

        System.out.println("\n✅ 遍历完成!");

        // 演示:可轻松替换为其他迭代器(如逆序)
        // 若实现 ReverseBookShelfIterator,只需替换 createIterator() 返回即可
        System.out.println("\n💡 说明:客户端代码无需修改即可支持不同遍历方式。");
        System.out.println("🔧 迭代器封装了遍历细节,书架内部可改为链表、树等结构。");
    }
}
实例对应的UML图(简化版)
implements
implements
has a
creates
gets iterator
uses for traversal
Book
-title: String
-author: String
+getTitle()
+getAuthor()
«interface»
Iterator<T>
+hasNext()
+next()
«interface»
Aggregate<T>
+createIterator()
BookShelf
-books: List<Book>
+addBook(book: Book)
+getSize()
+getBookAt(index: int)
+createIterator()
BookShelfIterator
-bookShelf: BookShelf
-currentIndex: int
+hasNext()
+next()
Client
+main(args: String[])

运行说明

  • BookShelf 是具体聚合类,内部使用 List<Book> 存储书籍。
  • BookShelfIterator 是具体迭代器,持有对 BookShelf 的引用和当前索引。
  • 客户端通过 createIterator() 获取迭代器,使用 hasNext()next() 安全遍历,无需知道 BookShelf 使用 List 实现。

四、总结

特性 说明
核心目的 统一访问聚合元素,隐藏内部结构
实现机制 迭代器对象封装遍历状态与逻辑
优点 解耦、支持多遍历方式、简化客户端、支持延迟计算
缺点 增加类数量、可能增加内存开销(迭代器对象)
适用场景 集合遍历、树/图遍历、数据库游标、流处理、外部API数据访问
不适用场景 遍历逻辑极其简单、性能极度敏感(少量元素)

迭代器模式使用建议

  • Java 集合框架(Collection/Iterator)是迭代器模式的标准实现。
  • 可实现只读迭代器可移除迭代器过滤迭代器转换迭代器等变体。
  • 支持泛型以提高类型安全。
  • 注意并发修改问题,可实现“快照迭代器”或“失败快速”机制。

架构师洞见:
迭代器模式是“关注点分离”与“接口抽象”的典范。在现代架构中,其思想已演变为流式编程(Stream API)响应式编程(Reactive Streams)数据管道的核心。例如,Java 8 的 Stream 是迭代器的高级抽象,支持链式操作(filter, map, reduce);在大数据处理中,Iterator 是处理海量数据流的基础(如 Hadoop RecordReader);在微服务中,分页 API 的 nextPageToken 本质是分布式迭代器;在前端框架中,虚拟列表(Virtual List)使用迭代器思想按需渲染。

未来趋势是:迭代器将与函数式编程深度融合,支持更复杂的组合操作;在AI 数据处理中,数据集迭代器(如 PyTorch DataLoader)是训练模型的关键;在边缘计算中,迭代器可实现低内存的流式数据处理;在量子计算中,状态叠加的遍历可能需要新型迭代器。

掌握迭代器模式,有助于设计出高内聚、低耦合、可复用的集合组件。作为架构师,应在设计任何容器类或数据访问层时,主动考虑使用迭代器。迭代器不仅是模式,更是数据访问的哲学——它告诉我们:真正的抽象,不在于隐藏数据,而在于提供一种安全、统一、可组合的方式来消费数据,让使用者专注于“做什么”,而非“如何做”。


网站公告

今日签到

点亮在社区的每一天
去签到