迭代器模式
迭代器模式
Rif设计模式笔记:迭代器模式 (Iterator Pattern)
一、一句话概括
提供一种统一的方法来顺序访问一个聚合对象(容器)中的各个元素,而无需暴露该对象的内部表示。
二、为什么需要它 (Why - The Pain Point)
我们有各种各样的数据集合,比如 ArrayList(基于数组)、LinkedList(基于链表)、HashSet(基于哈希表)、树、图等。每种数据结构的内部实现和元素存储方式都大相径庭。
痛点:
如果客户端代码想要遍历这些不同的集合,就必须为每一种集合编写不同的遍历逻辑。
1 | // 痛点:客户端代码与集合的具体实现紧密耦合 |
这种方式的问题是:
- 客户端代码复杂:客户端必须了解每种集合的内部数据结构。
- 耦合度高:客户端代码与
ArrayList,LinkedList等具体集合类紧密耦合。如果将来想把ArrayList换成LinkedList,所有遍历该集合的客户端代码都需要重写。 - 暴露内部实现:集合类被迫暴露其内部结构(如
getHead(),getNext()),这违反了封装原则。
核心问题:如何让客户端能够用一种统一、简单的方式遍历任何类型的集合,而无需关心集合的内部到底是怎么实现的?
三、它是什么 (What - The Solution)
迭代器模式将遍历的职责==从集合对象中分离出来,封装到一个独立的迭代器==(Iterator) 对象中。集合对象只负责创建并返回一个与其内部结构相匹配的迭代器实例。
核心思想和角色:
- **迭代器接口 (Iterator)**:
- 定义了遍历元素所需的标准方法。在 Java 中,通常是
hasNext()和next()。有时也包含remove()。
- 定义了遍历元素所需的标准方法。在 Java 中,通常是
- **具体迭代器 (Concrete Iterator)**:
- 实现了
Iterator接口,负责对特定的聚合对象进行遍历。 - 它内部需要持有一个对聚合对象的引用,并记录当前的遍历位置。
- 实现了
- **聚合接口 (Aggregate)**:
- 定义了一个创建迭代器的方法,通常是
createIterator()或iterator()。
- 定义了一个创建迭代器的方法,通常是
- **具体聚合 (Concrete Aggregate)**:
- 实现了
Aggregate接口,是具体的容器类(如ArrayList,LinkedList)。 - 它实现了
createIterator()方法,返回一个适合自身结构的具体迭代器实例。
- 实现了
工作流程:
客户端想遍历一个 MyList 对象,它不直接操作 MyList,而是:
- 调用
myList.iterator(),获得一个MyListIterator。 - 使用
while (iterator.hasNext()) { ... iterator.next() ... }的标准循环来处理元素。
客户端完全不知道MyList内部是数组还是链表,它只与标准的Iterator接口交互。
四、怎么做 (How - The Blueprint)
Java 已经为我们做好了这一切! java.util.Iterator 和 java.lang.Iterable 就是迭代器模式的完美实现。
java.lang.Iterable对应聚合接口。它只包含一个方法iterator()。java.util.Iterator对应迭代器接口。- 所有
java.util.Collection的子类(如ArrayList,LinkedList)都实现了Iterable,并提供了自己的具体迭代器实现(通常作为私有内部类)。
Java 示例代码 (利用Java内置支持)
1 | import java.util.ArrayList; |
五、UML 类图 (Java Collection Framework)
1 | @startuml |
六、优缺点分析
优点 (Pros):
- 封装和解耦:完美地将集合的内部结构与遍历行为解耦,客户端无需了解集合的实现细节。
- 统一的遍历接口:为所有类型的集合提供了统一的遍历方式,简化了客户端代码。
- 支持多种遍历方式:一个集合可以提供多种不同的迭代器(如正向、反向、跳跃等)。
- 安全地修改:迭代器的
remove()方法是遍历时修改集合的唯一安全方式,避免了并发修改异常 (ConcurrentModificationException)。 - 遵循单一职责原则:将遍历的逻辑从集合中移出,让集合专注于存储,迭代器专注于遍历。
缺点 (Cons):
- 增加类的数量:对于简单的集合,单独创建一个迭代器类可能会显得有点过度设计。但在 Java 中,这通常通过轻量级的内部类来解决,所以影响不大。