← 返回题目列表

迭代器模式有哪些角色?调用流程是什么?

高频 简单 第 1 / 25 题 更新于 2026/07/28
迭代器模式角色调用流程

简化版

迭代器模式通常包含迭代器接口、具体迭代器、聚合接口、具体聚合四类角色。调用流程是客户端从聚合对象获取迭代器,再通过迭代器逐个访问元素。

详细版

迭代器模式的角色包括:

  • Iterator:迭代器接口,定义 hasNext()next() 等遍历方法。
  • ConcreteIterator:具体迭代器,维护遍历位置并实现遍历逻辑。
  • Aggregate:聚合接口,定义创建迭代器的方法。
  • ConcreteAggregate:具体聚合,保存元素并返回对应迭代器。

客户端一般不直接访问集合内部结构,而是:

  1. 调用集合的 iterator()
  2. 拿到迭代器对象。
  3. 使用 hasNext() 判断。
  4. 使用 next() 取元素。

完整版教学

一、Iterator:迭代器接口

迭代器接口定义统一遍历能力。

interface MyIterator<E> {
    boolean hasNext();
    E next();
}

这个接口是客户端真正依赖的部分。只要不同集合都能返回这个接口,客户端遍历代码就能统一。

二、ConcreteIterator:具体迭代器

具体迭代器保存遍历状态,比如当前位置。

class ArrayIterator<E> implements MyIterator<E> {
    private final E[] elements;
    private int cursor = 0;

    ArrayIterator(E[] elements) {
        this.elements = elements;
    }

    public boolean hasNext() {
        return cursor < elements.length;
    }

    public E next() {
        return elements[cursor++];
    }
}

cursor 就是迭代器的游标状态。客户端不用自己维护下标。

三、Aggregate:聚合接口

聚合接口代表可被遍历的集合对象。

interface MyCollection<E> {
    MyIterator<E> iterator();
}

这个接口告诉客户端:我可以提供一个迭代器,但不会把内部结构直接给你。

四、ConcreteAggregate:具体聚合

具体聚合负责保存数据,并创建对应迭代器。

class MyArrayList<E> implements MyCollection<E> {
    private final E[] elements;

    MyArrayList(E[] elements) {
        this.elements = elements;
    }

    public MyIterator<E> iterator() {
        return new ArrayIterator<>(elements);
    }
}

如果以后底层改成链表,只需要返回链表迭代器,客户端遍历方式不变。

五、完整调用流程

调用过程可以拆成:

  1. 客户端拿到聚合对象。
  2. 客户端调用 iterator() 创建迭代器。
  3. 迭代器初始化自己的游标。
  4. 客户端循环调用 hasNext()
  5. 如果还有元素,调用 next() 获取元素。
  6. 迭代器推进游标。

这个流程中,集合负责提供数据来源,迭代器负责控制访问顺序。

六、为什么迭代器要单独成为对象

如果遍历状态放在集合对象里,同一个集合同时被两个地方遍历就会互相干扰。

例如一个循环走到第 3 个元素,另一个循环又从头开始,会覆盖集合内部游标。

把游标放进迭代器对象后,每次调用 iterator() 都可以得到独立遍历状态。多个遍历过程互不影响。

七、常见误区与追问

角色流程从 Aggregate 创建独立 Iterator 开始。客户端请求1个迭代器,迭代器保存 cursor 和集合引用,连续调用 next 直到结束;ConcreteAggregate 仍控制如何访问内部元素。若树做深度优先遍历,ConcreteIterator 还会保存显式栈,而客户端接口不变。

检查维度判定依据
Aggregate声明创建 Iterator 的能力
ConcreteIterator封装游标和具体遍历算法
Client -> Aggregate.iterator() -> Iterator -> elements

记忆钩子:集合保存数据,迭代器保存路程,客户端只问还有没有下一站。

  • 误区:Iterator 必须复制集合数据。 通常只持有引用和游标;快照型迭代器才会复制或固定视图。
  • 追问:一个 Aggregate 能返回多种 Iterator 吗? 可以,例如正序、逆序和层序遍历。
  • 误区:ConcreteAggregate 不参与遍历。 它提供底层访问能力并决定迭代器如何读取元素。
  • 追问:客户端为什么不直接读内部数组? 隐藏结构能让集合重构而不传播到所有调用方。
  • 追问:流程中版本号放在哪里? 集合维护 modCount,迭代器保存创建时的 expectedModCount。

八、加强记忆

迭代器模式的角色可以记成“两边四件套”:聚合接口和具体聚合负责存数据,迭代器接口和具体迭代器负责走数据;客户端只跟迭代器打交道。