ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

CS-Notes 设计模式精讲:迭代器(Iterator)模式——从意图、类图到 Java 实现与 JDK 容器应用

2026/9/7 23:00:14 拓冰建站 浏览量
CS-Notes 设计模式精讲:迭代器(Iterator)模式——从意图、类图到 Java 实现与 JDK 容器应用 CS-Notes 设计模式精讲迭代器Iterator模式——从意图、类图到 Java 实现与 JDK 容器应用【免费下载链接】CS-Notes:books: 技术面试必备基础知识、Leetcode、计算机操作系统、计算机网络、系统设计项目地址: https://gitcode.com/GitHub_Trending/cs/CS-Notes迭代器模式是 GoF 行为型设计模式中的经典一员本仓库的 设计模式笔记 将其归入行为型分类。这篇技术指南围绕 设计模式 - 迭代器.md 的完整内容展开讲清该模式的核心意图、类图中各角色职责、可运行的 Java 示例代码并结合本仓库 Java 容器.md 中关于 JDK 集合框架的源码分析说明java.util.Iterator、Iterable以及增强 for 循环背后真实的迭代器模式实践。读完你既能独立实现一个遍历与存储解耦的迭代器也能在阅读 JDK 集合源码时一眼识别出它的模式骨架。设计意图Intent把怎么遍历与存成什么结构解耦文档给出的一句话意图高度凝练了模式本质提供一种顺序访问聚合对象元素的方法并且不暴露聚合对象的内部表示。逐词拆开理解顺序访问无论底层是数组、链表、树还是哈希表都对外呈现统一的逐个取下一个元素的访问方式不暴露内部表示客户端拿不到聚合对象内部的items数组、链表节点等真实存储结构也就无法也不被允许直接依赖某个具体的数据布局来写遍历逻辑。由此带来的直接收益在代码层面可以清晰感知遍历逻辑与存储结构分离聚合对象负责存储迭代器负责游走各自职责单一聚合类可以自由更换内部数据结构只要createIterator()返回的迭代器行为不变客户端代码一行都不用改客户端只依赖接口编程客户端依赖的是Aggregate与Iterator两个抽象接口而不是它们的实现类这为后续扩展不同遍历策略留了空间。类图四个核心角色与一个 Client原文档给出的类图如下它完整刻画了迭代器模式的结构骨架结合类图与文档说明可以归纳出模式中的几类参与角色角色在类图中的位置职责Aggregate抽象聚合接口接口层声明createIterator()工厂式方法用于产生一个IteratorConcreteAggregate具体聚合实现层实现Aggregate内部持有真实元素集合本例为数组并返回包装了自身数据的ConcreteIteratorIterator抽象迭代器接口接口层定义遍历所需的两个核心方法hasNext()与next()ConcreteIterator具体迭代器实现层持有指向聚合元素集的引用与当前游标position实现真正的走一步看一步逻辑Client使用方组合依赖Aggregate通过createIterator()拿到Iterator完成遍历全程不触碰具体存储结构类图中传递的关键协作信息有两处虚线三角箭头实现关系ConcreteAggregate → Aggregate、ConcreteIterator → Iterator说明客户端依赖的永远是抽象接口而非具体类实线箭头依赖/关联关系Client依赖Aggregate与Iterator两个接口工作ConcreteAggregate与ConcreteIterator之间建立关联——具体聚合在createIterator()中把自身内部元素数组交给具体迭代器去遍历。这一设计让迭代成为聚合对象与客户端之间的中间人聚合暴露的不是元素结构而是一个能访问元素的迭代器。模式角色细化每个类该写什么原文档对类图角色的描述虽然简短但已经圈定了职责边界结合示例实现可以进一步细化Aggregate是聚合类其中createIterator()方法可以产生一个Iterator。它相当于给谁能被遍历立了一个统一契约任何想被客户端遍历的聚合都必须能交出迭代器。从实现手法看createIterator()扮演了创建迭代器对象的入口这与工厂方法的让创建过程对客户端透明思想同源。Iterator主要定义了hasNext()和next()两个方法。hasNext()回答还有没有下一个next()负责取出当前元素并把游标前移。这两个方法是最精简的遍历原语几乎所有语言内置的迭代器Java 的Iterator、Python 的__next__都围绕这一对语义展开。Client组合了Aggregate为了迭代遍历Aggregate也需要组合Iterator。Client 拿到的只是接口引用它不需要知道ConcreteIterator的存在更不需要知道元素存在数组的哪个下标遍历细节被完整封装在具体迭代器内部。这里还隐藏着一个值得注意的细节游标状态存放在迭代器里而不是聚合里。从下面的实现可以看到ConcreteIterator各自维护自己的position因此同一个聚合可以同时产生多个彼此独立的迭代器各自在不同位置推进互不干扰——这是把遍历状态从聚合中剥离出来的直接体现。基于 Java 的完整实现逐段拆解文档给出的实现由五个类组成两个接口、两个实现类和一个客户端入口。下面保持代码原貌并逐段说明它们如何协作。第一步定义抽象聚合接口Aggregatepublic interface Aggregate { Iterator createIterator(); }Aggregate是可遍历聚合的门面契约。它只声明一件事给我一个迭代器。任何存储类数组、List、Set甚至自定义的数据结构只要实现该接口就具备了统一的被遍历入口。第二步实现具体聚合ConcreteAggregatepublic class ConcreteAggregate implements Aggregate { private Integer[] items; public ConcreteAggregate() { items new Integer[10]; for (int i 0; i items.length; i) { items[i] i; } } Override public Iterator createIterator() { return new ConcreteIteratorInteger(items); } }ConcreteAggregate的内部表示是Integer[] items构造时依次填入0 ~ 9共 10 个元素。关键在createIterator()它把内部数组items原样传给新建的ConcreteIterator。这段代码清楚演示了聚合只负责存储与产出迭代器数组本身绝不直接泄漏给外部调用方。值得注意items被private私有化且没有对外 getter唯一的读取途径就是通过迭代器——这正是意图中不暴露内部表示的实现保障。第三步定义抽象迭代器接口IteratorItempublic interface IteratorItem { Item next(); boolean hasNext(); }Iterator接口引入了泛型Item让迭代结果带上类型信息避免客户端拿到元素后还要自行强转。两个抽象方法构成遍历的最小协议hasNext()判断当前游标之后是否还有元素next()返回当前位置元素并向前移动游标。第四步实现具体迭代器ConcreteIteratorpublic class ConcreteIteratorItem implements Iterator { private Item[] items; private int position 0; public ConcreteIterator(Item[] items) { this.items items; } Override public Object next() { return items[position]; } Override public boolean hasNext() { return position items.length; } }ConcreteIterator是模式中真正承载遍历逻辑的类它持有两样东西被遍历的数组引用items由聚合在createIterator()时注入迭代器只读不写保证遍历过程不破坏聚合数据游标position从 0 开始记录下一个待返回元素的位置。两个方法的实现非常直白且相互配合next()返回items[position]即取当前元素游标随后 1注意其返回值类型是Object——由于示例中该类实现的是原始类型raw typeIterator这属于教学示例的简化写法真实的 JDK 集合迭代器会完整使用泛型返回E类型元素hasNext()用position items.length判断游标是否越界避免next()越界抛出异常。遍历状态position被保存在迭代器实例内部而不是聚合对象上这意味着每个迭代器实例拥有独立的遍历进度可以在同一聚合上并发地推进多个游标。第五步编写客户端Client串起全流程public class Client { public static void main(String[] args) { Aggregate aggregate new ConcreteAggregate(); IteratorInteger iterator aggregate.createIterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } } }Client的调用序列完整演绎了模式的协作流程面向接口构造聚合声明类型是Aggregate而非ConcreteAggregate通过aggregate.createIterator()取得迭代器接收端类型是泛型化的IteratorInteger用while (iterator.hasNext()) { ... iterator.next(); }这一经典循环骨架逐元素取出并打印。程序运行后会在控制台依次输出0到9。整个过程中Client既没有引用ConcreteAggregate内部的数组也没有触碰ConcreteIterator的实现细节遍历逻辑以完全黑盒的方式完成。这个while hasNext() next()的三段式调用其实就是 Java 编译器处理增强 for 循环foreach时在背后生成的标准字节码模式——换句话说本例手工编写的循环正是 JDK 中for (Integer i : aggregate) {...}的手写原型。JDK 中的迭代器模式java.util 容器是如何贯彻它的原文档在 JDK 一节中点名了两个关键类java.util.Iteratorjava.util.Enumeration其中java.util.Iterator是 JDK 1.2 引入的标准迭代器接口定义了hasNext()、next()以及可选的remove()等默认方法java.util.Enumeration则是更早的遗留接口语义与之类似但方法名为hasMoreElements()/nextElement()体现了同一模式思想在新旧 API 中的两代实现。本仓库 Java 容器.md 的容器中的设计模式一节对此有更具体的剖析可以直接对照阅读Collection继承自IterableIterable中唯一的抽象方法iterator()正是迭代器模式的createIterator()在 JDK 中的化身——它返回一个Iterator对象调用方通过该对象即可遍历整个Collection的元素。见 Java 容器.md 相关描述。增强 for 循环foreach从 JDK 1.5 起任何实现了Iterable接口的聚合对象都可以直接用 foreach 遍历。仓库笔记中的示例代码正是模式最贴近日常的用法ListString list new ArrayList(); list.add(a); list.add(b); for (String item : list) { System.out.println(item); }遍历顺序由迭代器决定而非聚合保证由于迭代器是独立的遍历通道其顺序取决于具体实现。例如笔记明确指出HashSet使用Iterator遍历时得到的结果是不确定的因为哈希表本身不保留插入顺序信息——这正是存储结构与遍历方式解耦后客户端需要接受的语义边界。见 Java 容器.md 对 HashSet 的说明。fail-fast 机制的载体集合在结构上被并发修改时其迭代器会快速失败抛出ConcurrentModificationException。仓库笔记在 HashMap 的源码分析中提到HashMap 的迭代器是 fail-fast 迭代器说明迭代器不仅承担遍历职责还可以在遍历过程中承担并发安全的检测责任。见 Java 容器.md。从这一节的仓库证据可以看出Java 集合框架ArrayList、HashSet、HashMap等整体就是迭代器模式的最大规模生产级应用。任何具体集合只需实现iterator()并返回自己的迭代器实现就能无缝获得 foreach 语法与各种Collections工具方法的支持而调用方永远面向Iterator/Iterable接口编程。从模式到实践何时使用与设计要点小结综合原文档的意图、类图与实现可以沉淀出几条直接可用的判断标准当你想遍历一个聚合对象却不想暴露它的内部结构时用迭代器模式当聚合对象有多种遍历方式或希望同一聚合支持多个并行遍历游标时把遍历状态放进独立的迭代器对象而不是聚合本身当你想让客户端代码与具体存储结构解耦方便未来把数组换成链表、把List换成Set而不惊动调用方时依赖Aggregate与Iterator接口编程。从源码结构看本仓库这套设计模式笔记形成了完整的互链体系本文讲解的 设计模式 - 迭代器.md 属于行为型模式与 组合.md结构型树形整体/部分遍历在遍历场景上互为补充而模式在生产环境的落地证据则沉淀在 Java 容器.md 的源码分析中。把模式笔记 容器源码两篇对着读就能把抽象的模式语言翻译成看得见、跑得起来的 JDK 工程实践。【免费下载链接】CS-Notes:books: 技术面试必备基础知识、Leetcode、计算机操作系统、计算机网络、系统设计项目地址: https://gitcode.com/GitHub_Trending/cs/CS-Notes创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考