在日常开发中,迭代器模式(Iterator Pattern)是我们时时刻刻都在用,但却存在感最小的一种设计模式。对于普通的 Java 业务开发者来说,我们基本上不会去单独写一个迭代器模式,这是因为大部分常用的容器都已经提供了迭代器模式的实现了,如 List、Set 等等。
即便是自定义的容器,我们也不会去自己写迭代器的实现,而是用 JDK 中提供的迭代器接口——Iterator。今天就以 JDK 中提供的迭代器模式最佳实践 Iterator 接口来介绍该模式。

1. 定义
迭代器模式是一种行为型设计模式,它的定义是:“它提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节。”
定义中描述了迭代器模式解决的问题:提供遍历容器元素的方法。同时还描述了使用迭代器模式提供此方法的优势:不需要暴露容器的内部细节。
什么叫不需要暴露容器的内部细节?暴露容器内部细节有什么问题吗?
如果遍历容器需要暴露容器的内部细节,则意味在开发者在对容器元素进行删除时,由于容器整体元素减1,还需要将当前遍历元素的索引数向前移动一位,这样才不会在后面的遍历过程中发生类似于数组越界的异常。
而如果将容器内部细节隐藏,则开发者在对容器进行增删操作的时候,并不需要关心当前遍历元素索引的位置,降低了复杂度。
2. 类图
在迭代器模式中,有这样几种角色:
- 抽象聚合角色(Aggregate):定义容器的增删方法以及创建迭代器的方法
- 具体聚合角色(ConcreteAggregate):抽象聚合接口的实现类
- 抽象迭代器角色(Iterator):定义遍历容器的方法,如 next()、hasNext() 方法
- 具体迭代器角色(Concretelterator):抽象迭代器接口的实现类,实现对容器的遍历方法
迭代器模式的类图如下:
3. 示例
迭代器模式的最佳实践,JDK 已经做的非常好了,下面我们就来新建一个用户优惠券的容器类实现 JDK 提供的 Iterator 接口来实现用户优惠券的快速遍历。
首先看一下 JDK 提供的 Iterator 接口源码:
public interface Iterator<E> {// 判断是否有下一个元素boolean hasNext();// 返回下一个元素E next();// 默认不支持删除default void remove() {throw new UnsupportedOperationException("remove");}// 省略 forEachRemaining 方法}
然后定义容器中的元素优惠券类以及持有优惠券列表的用户,其代码如下:
public class Coupon {private String name;public Coupon(String name) {this.name = name;}// 省略 setter/getter 方法}public class UserCoupon {private List<Coupon> list = new ArrayList<>();public void add(Coupon coupon) {list.add(coupon);}public void remove(Coupon coupon) {list.remove(coupon);}public Iterator<Coupon> getIterator() {return list.iterator();}}
然后编写测试代码:
public class Test {public static void main(String[] args) {UserCoupon userCoupon = new UserCoupon();userCoupon.add(new Coupon("满100-10券"));userCoupon.add(new Coupon("满200-20券"));userCoupon.add(new Coupon("满300-30券"));Iterator<Coupon> iterator = userCoupon.getIterator();while (iterator.hasNext()) {Coupon next = iterator.next();System.out.println(next.getName());}}}
输出结果为:
满100-10券满200-20券满300-30券
可能上面的示例有点画蛇添足多此一举,但是返回迭代器能直接用 iterator.next() 是因为 List 接口原本就实现了迭代器的功能,否则实现迭代器模式还需要定义很多其他逻辑。
有兴趣的同学可以自己去看一看 ArrayList 的代码中关于迭代器的部分,写得还是比较清楚的。
4. 使用场景
迭代器模式的使用场景是:
- 访问一个聚合对象的内容且无须暴露其内部细节
- 需要为访问聚合对象提供多种不同的遍历方法时,可以使用迭代器模式对这些遍历方法进行统一抽象
5. 小结
本文讲述了迭代器模式,它的定义是——它提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节。
迭代器模式的优点是:
- 访问一个聚合对象的内容且无须暴露其内部细节
- 访问聚合对象功能由迭代器实现,与聚合类解耦
- 拓展性良好,新增访问方法只需要新增迭代器子类即可
迭代器模式的缺点是:
- 如果存在很多迭代方法,一定程序上增加了系统的复杂度
6. 参考资料
- 《设计模式之禅》(第2版)
- 迭代器模式(详解版)
最后,本文收录于个人语雀知识库: 我所理解的后端技术,欢迎来访。
