循环岁月,犹如流水,迭代器之舟,悠然穿梭。
一、集合的遍历
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Element 1");
list.add("Element 2");
list.add("Element 3");
// 需要直接访问集合对象的内部结构来遍历元素
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
上述代码,是集合遍历的一种方式。可是我们若仔细思考会发现这种遍历方式存在一些问题:
- 代码复用性差:这段代码只能用于遍历 ArrayList 类型的集合。如果我们需要遍历其他类型的集合(如 Set 或 Map),我们可能需要编写新的代码。
- 代码耦合度高:这段代码直接依赖于 ArrayList 的 size() 和 get() 方法。如果 ArrayList 的实现发生变化,或者我们需要遍历的集合不支持 size() 和 get() 方法,那么这段代码可能就无法工作。
- 违反封装原则:这段代码直接访问了 ArrayList 的内部结构(通过 size() 和 get() 方法)。这违反了封装原则,使得 ArrayList 的内部实现细节暴露给了外部。
二、迭代器模式
迭代器模式是一种行为型
设计模式,它用于提供一种方法来顺序访问一个聚合对象中的各个元素,而不需要暴露该对象的内部表示。在迭代器模式中,迭代器对象负责跟踪聚合对象的当前位置,并且提供访问元素的接口。
这种模式对于处理集合(如列表、数组等)中的元素非常有用,因为它使得遍历集合的过程变得更加简洁和灵活。通过迭代器,客户端代码可以在不知道集合内部结构的情况下,访问集合中的元素。
三、迭代器模式的核心组成
迭代器模式的核心组件主要包括以下几个部分:
- 迭代器接口(Iterator):这是一个接口,定义了用于遍历聚合对象的通用操作,如获取下一个元素、判断是否存在下一个元素等。
- 具体迭代器(Concrete Iterator):这是实现迭代器接口的具体实现类,为特定容器类型提供具体的迭代方法。
- 聚合接口(Aggregate):这是一个接口,定义了创建迭代器对象的方法。
- 具体聚合(Concrete Aggregate):这是实现聚合接口的具体实现类,为特定容器类型提供创建迭代器的方法
在这个类图中:
Iterator
是迭代器接口,定义了 hasNext() 和 next() 方法。ConcreteIterator
是具体迭代器,实现了 Iterator 接口,并保存了对 ConcreteAggregate 的引用以及当前的索引位置。Aggregate
是聚合接口,定义了 createIterator() 方法。ConcreteAggregate
是具体聚合,实现了 Aggregate 接口,并返回一个 ConcreteIterator 对象。
四、运用迭代器模式
场景假设:使用自定义迭代器实现集合的遍历
-
定义迭代器接口:首先,我们需要定义一个迭代器接口,该接口包含两个方法:hasNext() 和 next()。hasNext() 方法用于检查是否还有下一个元素,next() 方法用于获取下一个元素。
// 迭代器接口 public interface Iterator { boolean hasNext(); // 判断是否有下一个元素 Object next(); // 获取下一个元素 }
-
实现具体迭代器:然后,我们需要为我们的集合类实现一个具体的迭代器。这个迭代器需要保存当前遍历的位置,并在 next() 方法中返回当前位置的元素并将位置向前移动一位。
// 具体迭代器 public class ConcreteIterator implements Iterator { private ArrayList list; // 聚合对象 private int index = 0; // 当前遍历的位置 public ConcreteIterator(ArrayList list) { this.list = list; // 初始化聚合对象 } @Override public boolean hasNext() { return index < list.size(); // 判断是否有下一个元素 } @Override public Object next() { return hasNext() ? list.get(index++) : null; // 获取下一个元素 } }
-
定义聚合接口:我们需要定义一个聚合接口,该接口包含一个方法:createIterator()。createIterator() 方法用于创建一个迭代器。
// 聚合接口 public interface Aggregate { Iterator createIterator(); // 创建迭代器 }
-
实现具体聚合:最后,我们需要为我们的集合类实现一个具体的聚合。在这个聚合中,我们需要实现 createIterator() 方法,该方法返回一个新的迭代器实例。
// 具体聚合 public class ConcreteAggregate implements Aggregate { private ArrayList list = new ArrayList(); // 内部存储元素的列表 @Override public Iterator createIterator() { return new ConcreteIterator(list); // 创建具体迭代器 } // 其他方法,如添加元素、删除元素等 public void add(Object obj) { list.add(obj); } }
-
客户端:测试迭代器遍历集合
// 客户端代码 public class Client { public static void main(String[] args) { // 创建具体聚合对象 ConcreteAggregate aggregate = new ConcreteAggregate(); // 添加元素 aggregate.add("Element 1"); aggregate.add("Element 2"); aggregate.add("Element 3"); // 创建迭代器 Iterator iterator = aggregate.createIterator(); // 使用迭代器遍历元素 while (iterator.hasNext()) { System.out.println(iterator.next()); } } }
五、迭代器模式的应用场景
迭代器模式在许多场景中都有应用,特别是对集合中的元素进行遍历并访问每个元素时,它会非常有用。以下是一些常见的应用场景:
- 遍历复杂数据结构:使用迭代器模式可以方便地遍历复杂数据结构,如链表、树、图等,而不需要知道数据结构的内部细节。
- 分离容器和遍历:使用迭代器模式可以将容器和遍历操作分离,使得我们可以更灵活地使用不同的迭代器来遍历同一个集合,根据需求选择不同的遍历方式。
- 支持多种遍历方式:使用迭代器模式可以轻松地支持多种遍历方式,如正序遍历、倒序遍历、深度优先遍历、广度优先遍历等。
六、小结
迭代器模式是一种强大而灵活的设计模式,它提供了一种简单而优雅的方法来遍历集合对象。通过将集合的遍历算法与集合本身分离开来,迭代器模式使得我们可以轻松地处理不同类型的集合,并且可以根据需要轻松地切换遍历策略。