0%

迭代器模式

迭代器模式(Iterator Pattern):统一访问集合元素的方式

迭代器模式是行为型设计模式的一种,核心思想是提供一种统一的方法顺序访问容器对象(如集合、数组)中的各个元素,而不暴露容器的内部结构。这种模式就像 “遥控器”—— 无论电视机的内部构造如何,用户只需通过遥控器的按键(迭代器方法)就能逐频道切换(遍历元素),无需了解电视的内部细节。

迭代器模式的核心结构

迭代器模式通过四个核心角色实现对容器元素的统一遍历,职责明确且解耦了容器与遍历逻辑:

迭代器接口(Iterator)

  • 定义遍历容器元素的标准接口,通常包含以下方法:
    • hasNext():判断是否还有下一个元素。
    • next():返回当前元素,并移动到下一个位置。
    • (可选)remove():移除当前元素(视容器支持情况)。
  • 示例:java.util.Iterator(Java 集合框架的迭代器接口)。

具体迭代器(ConcreteIterator)

  • 实现迭代器接口,封装具体的遍历逻辑,记录当前遍历位置,与特定容器绑定。
  • 示例:ArrayList的内部迭代器(遍历数组)、LinkedList的内部迭代器(遍历链表)。

容器接口(Collection/Aggregate)

  • 定义容器的核心接口,声明创建迭代器的方法(iterator()),是所有容器的抽象父类。
  • 示例:java.util.Collection(Java 集合的根接口)。

具体容器(ConcreteCollection)

  • 实现容器接口,存储元素并提供创建对应迭代器的方法,负责管理元素的增删改查。
  • 示例:ArrayList(数组容器)、HashSet(哈希表容器)。

代码实现示例

以 “自定义列表容器” 为例,展示迭代器模式的实现:自定义MyList容器,通过迭代器遍历元素,不暴露内部存储结构(如数组)。

1. 迭代器接口与具体迭代器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 1. 迭代器接口
public interface MyIterator<E> {
boolean hasNext(); // 是否有下一个元素
E next(); // 获取下一个元素
}

// 2. 具体迭代器(与MyArrayList绑定)
public class MyArrayListIterator<E> implements MyIterator<E> {
private MyArrayList<E> list; // 关联的容器
private int index = 0; // 当前遍历索引

public MyArrayListIterator(MyArrayList<E> list) {
this.list = list;
}

@Override
public boolean hasNext() {
return index < list.size(); // 索引未超出容器大小则有下一个元素
}

@Override
public E next() {
if (!hasNext()) {
throw new NoSuchElementException("没有更多元素");
}
return list.get(index++); // 返回当前元素并移动索引
}
}

2. 容器接口与具体容器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// 3. 容器接口
public interface MyCollection<E> {
void add(E element); // 添加元素
E get(int index); // 获取指定位置元素
int size(); // 获取元素数量
MyIterator<E> iterator(); // 创建迭代器
}

// 4. 具体容器(基于数组实现)
public class MyArrayList<E> implements MyCollection<E> {
private Object[] elements; // 内部存储结构(数组,不暴露给外部)
private int size = 0; // 元素数量

public MyArrayList(int capacity) {
elements = new Object[capacity];
}

@Override
public void add(E element) {
if (size < elements.length) {
elements[size++] = element;
} else {
throw new IndexOutOfBoundsException("容器已满");
}
}

@Override
public E get(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("索引越界");
}
return (E) elements[index];
}

@Override
public int size() {
return size;
}

@Override
public MyIterator<E> iterator() {
// 返回与当前容器绑定的迭代器
return new MyArrayListIterator<>(this);
}
}

3. 客户端使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class IteratorDemo {
public static void main(String[] args) {
// 创建容器并添加元素
MyCollection<String> list = new MyArrayList<>(5);
list.add("元素1");
list.add("元素2");
list.add("元素3");

// 获取迭代器并遍历
MyIterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String element = iterator.next();
System.out.println(element);
}
}
}
输出结果
1
2
3
元素1
元素2
元素3

迭代器模式的核心优势

  1. 统一遍历接口
    无论容器内部结构是数组、链表还是哈希表,客户端都可通过相同的hasNext()next()方法遍历,无需关心容器的具体实现(如ArrayListLinkedList的遍历代码完全一致)。
  2. 隐藏容器内部结构
    客户端仅通过迭代器访问元素,无需知道容器是用数组还是链表存储的,降低了客户端与容器的耦合度,保护了容器的封装性。
  3. 支持多种遍历方式
    一个容器可提供多个迭代器实现不同的遍历逻辑(如正向遍历、反向遍历、过滤遍历),客户端可根据需求选择。
  4. 简化容器接口
    容器无需暴露大量遍历相关的方法(如get(int index)可能仅用于内部),只需提供iterator()方法即可。

适用场景

  1. 需要统一遍历不同容器
    当系统中存在多种容器(如数组、集合、树),且希望用相同的代码遍历它们时(如 Java 集合框架的for-each循环)。
  2. 不希望暴露容器内部结构
    容器的内部实现(如哈希表的桶数组、链表的节点)属于私有细节,不应暴露给客户端,迭代器是安全的访问方式。
  3. 需要多种遍历方式
    如对列表需要正向遍历、反向遍历或按条件筛选遍历,可通过不同的迭代器实现。
  4. 迭代逻辑复杂或易变
    将遍历逻辑封装在迭代器中,便于修改或扩展(如优化遍历性能),不影响容器本身。

优缺点分析

优点

  • 遍历接口统一:客户端代码更简洁,无需针对不同容器编写不同遍历逻辑。
  • 封装性好:容器内部结构对客户端透明,降低耦合度。
  • 扩展性强:新增容器或迭代方式时,只需实现对应的容器和迭代器接口,不影响现有代码。

缺点

  • 额外的类开销:每个容器需对应一个或多个迭代器类,增加了系统的类数量。
  • 迭代器与容器绑定:迭代器依赖于特定容器,更换容器可能需要更换迭代器(但客户端无需修改遍历代码)。

经典应用:Java 集合框架的迭代器

Java 的java.util.Iterator是迭代器模式的典范,几乎所有集合类(ArrayListHashMapTreeSet等)都实现了Iterator接口,使遍历代码高度统一:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 遍历ArrayList
List<String> arrayList = new ArrayList<>();
arrayList.add("A");
arrayList.add("B");
Iterator<String> it1 = arrayList.iterator();
while (it1.hasNext()) {
System.out.println(it1.next());
}

// 遍历HashSet(代码完全相同)
Set<String> hashSet = new HashSet<>();
hashSet.add("X");
hashSet.add("Y");
Iterator<String> it2 = hashSet.iterator();
while (it2.hasNext()) {
System.out.println(it2.next());
}

甚至可通过增强 for 循环(for-each)简化遍历,其底层仍依赖迭代器:

1
2
3
for (String s : arrayList) {
System.out.println(s);
}

总结

迭代器模式通过分离容器与遍历逻辑,提供了一种统一、安全的元素访问方式,是处理集合类数据的核心模式。其核心价值在于 “接口统一” 和 “封装内部结构”,使客户端能专注于元素的使用而非容器的实现

欢迎关注我的其它发布渠道

表情 | 预览
快来做第一个评论的人吧~
Powered By Valine
v1.3.10