设计模式源码git地址:design-pattern-src: 设计模式源码 (gitee.com)

  1. 定义
  2. 为什么需要
  3. 常见写法
  4. 角色
  5. 场景举例
  6. 总结

定义

提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示

为什么需要迭代器模式

在我们遍历元素的时候,不能将内部元素的数据结构(如数组,集合)暴露给用户。需要保证数据安全性。其次也增加了用户的负担,它原本也不需要知道内部结构

常见的迭代器写法

1
2
3
4
5
6
List<String> list = new ArrayList<>(); 
Iterator iter = list.iterator();
while(iter.hasNext()){
String str = (String) iter.next();
System.out.println(str);
}

日常开发中不需要重复造轮子,框架给的API就够用了,自己模拟实现迭代器实现如下

1
2
3
4
5
MyIterable<Student> list = new ConcreteIterable();
MyIterator iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}

可以将MyIterable看作ArrayList

因为ArrayList内部实现了Iterable接口(实际上是Collection接口实现的,List继承了相关父类而得到的能力)

角色

抽象聚合(MyIterable)角色:定义创建迭代器对象的接口。

具体聚合(ConcreteIterable)角色:实现抽象聚合类,返回一个具体迭代器的实例。

抽象迭代器(Iterator)角色:定义访问和遍历聚合元素的接口,通常包含 hasNext()、next() 等方法。

具体迭代器(ConcreteIterator)角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。

场景举例

假如需要遍历一个学生对象类

uml类图

img

首先建立学生类

1
2
3
4
5
public class Student {
private int id;
private String name;
//get、set、构造器、toString省略
}

迭代器能力接口,使实现的子类具有迭代器的能力

1
2
3
public interface MyIterable<E> {
MyIterator iterator();
}

迭代器接口,定义遍历条件与遍历过程

1
2
3
4
5
public interface MyIterator<E> {
boolean hasNext();

E next();
}

具体实现类实现两个接口,进行方法重写

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
public class ConcreteIterable implements MyIterable<Student> {
private List<Student> list = new ArrayList<>();
public ConcreteIterable() {
//做简化
list.add(new Student(1,"小王"));
list.add(new Student(2,"小李"));
list.add(new Student(3,"小张"));
}

@Override
public MyIterator iterator() {
return new ConcreteIterator();
}

public boolean addStudent(Student s) {
return list.add(s);
}

public boolean removeStudent(Student s) {
return list.remove(s);
}

//参照ArrayList实现方式
private class ConcreteIterator implements MyIterator<Student> {

private int index = 0;

@Override
public boolean hasNext() {
return index < list.size();
}

@Override
public Student next() {
return list.get(index++);
}
}
}

客户端调用就是最上面的

结果输出

1
2
3
Student{id=1, name='小王'}
Student{id=2, name='小李'}
Student{id=3, name='小张'}

总结

该模式与聚合对象关系密切,通常在以下场景中使用

  1. 当需要为聚合对象提供多种遍历方式时。
  2. 当需要为遍历不同的聚合结构提供一个统一的接口时。
  3. 当访问一个聚合对象的内容而无须暴露其内部细节的表示时

而大多数语言在实现据合类的时候已经提供了迭代器类,用本身自带的就足够了

具体的源码可以参照JDK提供的Iterator、Iterable、ArrayList等