迭代器模式(Iterator Pattern)又称为游标(Cursor)模式,是最常被使用的几个模式之一,被广泛地应用到 Java 的 API 中。例如,Java 的集合(Collection)框架中,就广泛使用迭代器来遍历集合中的元素。
定义
迭代器模式的英文定义如下:
Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
意思是:提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节。
迭代器是为容器服务的,容器是指用来容纳其他对象的对象,例如,Collection 集合类型、Set 类等。
组成角色
迭代器模式有以下 4 个角色:
- 抽象迭代器(Iterator)角色:该角色负责定义访问和遍历元素的接口;
- 具体迭代器(Concrete Iterator)角色:该角色实现 Iterator 接口,完成容器元素的遍历;
- 抽象聚集(Aggregate)角色:该角色提供创建迭代器角色的接口;
- 具体聚集(Concrete Aggregate)角色:该角色实现抽象聚集接口,创建出容纳迭代器的对象。
角色之间的关系,如下图所示:
迭代器模式代码实现
抽象迭代器
interface Iterator {
public Object next();
public boolean hasNext();
}
具体迭代器
class ConcreteIterator implements Iterator {
private ConcreteAggregate aggregate;
private int index;
private int size;
public ConcreteIterator(ConcreteAggregate aggregate) {
this.aggregate = aggregate;
this.index = 0;
this.size = aggregate.size();
}
// 是否有下一个元素
@Override
public boolean hasNext() {
return index < size;
}
// 返回下一个元素
@Override
public Object next() {
if (index < size) {
return aggregate.getElement(index++);
}
return null;
}
}
抽象聚集
interface Aggregate {
public void add(Object obj);
public Iterator createIterator();
}
具体聚集
class ConcreteAggregate implements Aggregate {
// 私有存储容器
private Vector vector = new Vector();
// 添加元素
@Override
public void add(Object obj) {
this.vector.add(obj);
}
// 根据下标获取元素
public Object getElement(int index) {
return vector.get(index);
}
// 获取集合长度
public int size() {
return vector.size();
}
// 创建迭代器
@Override
public Iterator createIterator() {
return new ConcreteIterator(this);
}
}
客户端
public class Client {
public static void main(String[] args) {
// 定义聚族对象
Aggregate aggregate = new ConcreteAggregate();
aggregate.add("Java");
aggregate.add("MySQL");
aggregate.add("Spring");
// 遍历
Iterator iterator = aggregate.createIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
程序执行结果:
Java
MySQL
Spring
优缺点
迭代器模式的优点:
- 迭代器模式将数据存储和数据遍历的职责进行分离;
- 迭代器模式简化了遍历容器元素的操作;
- 迭代器模式使不同的容器,具备一个统一的遍历接口;
- 迭代器模式封装了遍历算法,使算法独立于聚集角色,调用者无须知道聚集对象的类型,即使聚集对象的类型发生变化,也不会影响遍历过程。
迭代器模式的缺点: - 由于迭代器模式将数据存储和数据遍历的职责进行分离,如果增加新的聚合类,同时需要增加与之相对应的迭代器类,这使得类的个数会成对增加,在某种程度上来说增加了系统的复杂性。
应用场景
迭代器的应用很广泛,已经发展成为程序开发中最基础的工具类了。在 Java 语言中,从 JDK 1.2 开始,增加了 java.util.Iterator 接口,并将 Iterator 应用到各个聚集类(Collection)中,如 ArrayList、Vector、Stack、HashSet 等集合类都实现了 iterator() 方法,返回一个迭代器 Iterator,用于对集合中的元素进行遍历。这使我们在项目中无须在独立地写迭代器,直接使用即可,这样既轻松又便捷。
注意:要尽可能地使用编程语言自身提供的迭代器,而非自己写的迭代器。
使用实例
下面将会使用 Java API 提供的迭代器模式,演示迭代器的具体使用。
public class Lesson19 {
public static void main(String[] args) {
// 调用迭代器应用示例
new IteratorUseDemo().doIterator();
}
}
/**
* 迭代器应用——演示示例
*/
class IteratorUseDemo {
void doIterator() {
// 定义 Vector 集合
Vector vector = new Vector();
vector.add("Vector 1");
vector.add("Vector 2");
vector.add("Vector 3");
// 定义 ArrayList 集合
ArrayList list = new ArrayList();
list.add("ArrayList 1");
list.add("ArrayList 2");
list.add("ArrayList 3");
// 使用迭代器循环 Vector
java.util.Iterator vIterator = vector.iterator();
while (vIterator.hasNext()) {
System.out.println(vIterator.next());
}
// 使用迭代器循环 ArrayList
java.util.Iterator lIterator = list.iterator();
while (lIterator.hasNext()) {
System.out.println(lIterator.next());
}
}
}
程序执行结果:
Vector 1
Vector 2
Vector 3
ArrayList 1
ArrayList 2
ArrayList 3
从上面示例可以看出,集合都可以通过 iterator() 方法,获得统一的迭代器对象 java.util.Iterator,然后进行循环遍历。
总结
迭代器模式是最常用的设计模式之一,已经被广泛应用到 Java 的 API 中,比如在 Java 的集合中,使用 iterator() 方法就可以获得统一的迭代器对象 java.util.Iterator,使用这个对象就可以很方便地实现集合的遍历功能。迭代器包含四个角色(抽象迭代器、具体迭代器、抽象聚集和具体聚集)和两个重要的方法:hasNext() 方法用来判断是否还有下一个未遍历的元素,next() 方法用来获取此次遍历的对象。要注意的是,如果编程语言中已经提供了内置的迭代器,并且能满足现有需求的情况下,开发者就不必自己再写迭代器了。