Java设计模式(22)-迭代器模式
生活中,存在这样的场景:需要逐个遍历一堆对象,然后判断对象是否符合要求,做出相应的处理。例如,乘火车时,检票员站在门口挨个检票,没有买票的人不能乘车。类似的场景还有很多,比如乘地铁、乘公交、从书架上找书、食堂排队打饭等等…… 我们把需要逐个遍历的这一堆对象称为 对象集合,把挨个遍历的过程称为 迭代。迭代时,如果能将迭代过程从对象集合中抽取出来单独实现,让对象集合只负责管理自身状态,而不用负担迭代的任务,这就减轻了对象集合的职责,这就是今天要说的——迭代器模式。 也许你会想,对象集合不就是 List 吗,直接使用 "增强for循环" 遍历不就完成迭代过程了吗?说的没错!迭代器模式在很多面向对象的语言中都已经内置了,比如 Iterator,所以我们大多数情况下不会再自己实现它,但是学习模式本身的原理还是非常有必要。 1. 概念 DP对迭代器模式的定义如下:迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。 这个定义还是比较抽象,简单而言:迭代器模式,提倡将聚合对象(就是前边提的 "对象集合")的迭代逻辑抽取成一个 迭代器,聚合对象本身只需要提供一个返回迭代器的方法即可,而不需要关注迭代逻辑。客户端拿到对象集合的迭代器,就可以遍历了。 这种由客户端来决定如何遍历的方式,被称为 外部(主动)迭代器;还有一种迭代方式,客户端调用一个方法告诉聚合对象它的每一个元素该如何处理,然后由聚合对象内部负责迭代,这被称为 内部(被动)迭代器。Java 两种都支持,比如外部用增强for循环遍历 List,就是外部迭代器,而调用 List 的 forEach(Consumer<? super T> action) 方法,或者调用 Iterator 的 forEachRemaining(Consumer<? super E> action) 方法就属于内部迭代器。 聚合对象中的元素并不一定是有序存储的,比如 Set。此外,迭代器除了从头开始遍历聚合对象,还可以实现从尾部开始遍历,这取决于具体实现。比如,Java 提供了 ListIterator 支持双向迭代,它继承自 Iterator。 2. 结构 迭代器模式的结构如下图所示: 这里我使用的Java的泛型方式来定义的类,标准的迭代器模式显然没有泛型。从图可知,迭代器模式一共分为四个角色: Aggregate<T>: 抽象聚合对象,定义了通用的接口方法,通常是一个对象集合,支持存储多个对象,并支持创建一个迭代器。如 Java的 List、Set、Coleection 等接口 Iterator<T>: 抽象迭代器,定义了迭代的接口方法,如 next 迭代下一个对象,hasNext() 返回是否还有下一个对象等等 ConcreteIterator<T>: 具体迭代器实现,一个 Aggregate 可能存在多个迭代器实现 ConcreteAggregate<T>: 具体聚合对象,如 Java中的 ArrayList,HashSet 等等 ...