迭代器模式

基本介绍

  • 迭代器模式( lterator Pattern)是常用的设计模式,属于行为型模式
  • 如果我们的集合元素是用不同的方式实现的,有数组,还有java的集合类,或者还有其他方式,当客户端要遍历这些集合元素的时候就要使用多种遍历方式,而且还会暴露元素的内部结构,可以考虑使用迭代器模式解决。
  • 迭代器模式,提供一种遍历集合元素的统一接口用一致的方法遍历集合元素,不需要知道集合对象的底层表示,即:不暴露其内部的结构。
image-20220112113919441
  • 抽象容器:一般是一个接口,提供一个iterator()方法,例如java中的Collection接口,List接口,Set接口等。一个统一的聚合接口,将客户端和具体聚合解耦。
  • 具体容器:就是抽象容器的具体实现类,比如List接口的有序列表实现ArrayList,List接口的链表实现LinkList,Set接口的哈希列表的实现HashSet等。
  • 抽象迭代器:定义遍历元素所需要的方法,一般来说会有这么三个方法:取得第一个元素的方法first(),取得下一个元素的方法next(),判断是否遍历结束的方法isDone()(或者叫hasNext()),移出当前对象的方法remove(),
  • 迭代器实现:实现迭代器接口中定义的方法,完成集合的迭代。

解决问题

如果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
public class Department {

private String name;
private String desc;

public Department(String name, String desc) {
this.name = name;
this.desc = desc;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getDesc() {
return desc;
}

public void setDesc(String desc) {
this.desc = desc;
}
}

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
public class InfoCollegeIterator implements Iterator {

//这里需要知道Department是以怎么样存放的
List<Department> departments; //是以list
//遍历位置
int index = -1;

public InfoCollegeIterator(List<Department> departments) {
this.departments = departments;
}

@Override
public boolean hasNext() {
if (index >= departments.size() - 1){
return false;
}
index ++;
return true;
}

@Override
public Object next() {
return departments.get(index);
}
}
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
public class ComputerCollegeIterator implements Iterator {

//这里需要知道Department是以怎么样存放的,这里是数组
Department[] departments;
//遍历位置
int position = 0;

public ComputerCollegeIterator(Department[] departments) {
this.departments = departments;
}

//判断是否还有下一个
@Override
public boolean hasNext() {
if (position >= departments.length || departments[position] == null){
return false;
}
return true;
}

@Override
public Object next() {
Department department = departments[position];
position++;
return department;
}
}

大学接口类

1
2
3
4
5
6
7
8
public interface College {

public String getName();

public void addDepartment(String name, String desc);

public Iterator createIterator();
}
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
public class ComputeCollege implements College {

Department[] departments;
int numOfDepartment = 0; //保存数组对象个数

public ComputeCollege(){
departments = new Department[5];
addDepartment("Java","");
addDepartment("PHP","");
addDepartment("大数据","");
}

@Override
public String getName() {
return "计算机学院";
}

@Override
public void addDepartment(String name, String desc) {
Department department = new Department(name, desc);
departments[numOfDepartment] = department;
numOfDepartment ++;
}

@Override
public Iterator createIterator() {
return new ComputerCollegeIterator(departments);
}
}
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
public class InfoCollege implements College{

List<Department> departments;

public InfoCollege(){
departments = new ArrayList<>();
addDepartment("Java","");
addDepartment("PHP","");
addDepartment("大数据","");
}

@Override
public String getName() {
return "信息工程学院";
}

@Override
public void addDepartment(String name, String desc) {
Department department = new Department(name, desc);
departments.add(department);
}

@Override
public Iterator createIterator() {
return new InfoCollegeIterator(departments);
}
}

输出类

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
public class OutPutImpl {

//学院集合
List<College> collegeList;

public OutPutImpl(List<College> collegeList){
this.collegeList = collegeList;
}

//
public void printCollege(){
Iterator<College> iterator = collegeList.iterator();
while (iterator.hasNext()){
//取出一个学院
College college = iterator.next();
System.out.println("========="+ college.getName() +"========");
printDepartment(college.createIterator());
}
}

//输出
public void printDepartment(Iterator iterator){
while (iterator.hasNext()){
Department d = (Department) iterator.next();
System.out.println(d.getName());
}
}
}

客户端

1
2
3
4
5
6
7
8
9
public class Client {
public static void main(String[] args) {
List<College> collegeList = new ArrayList<>();
collegeList.add(new ComputeCollege());
collegeList.add(new InfoCollege());
OutPutImpl outPut = new OutPutImpl(collegeList);
outPut.printCollege();
}
}

源码分析

ArrayList

ArrayList实现了List接口,List接口实现了Collection接口,Collection实现了Iterable接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public interface Iterable<T> {

Iterator<T> iterator();


default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}

default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
}

Iterable提供了iterator接口。ArrayList实现了具体的iterator接口:

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
46
47
48
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
transient Object[] elementData;

public Iterator<E> iterator() {
return new Itr();
}
//内部类
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;

Itr() {}

public boolean hasNext() {
return cursor != size;
}

@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}

public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();

try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}

Itr这个内部类实现了Iterator接口,ArrayList使用elementData存放数据,并没有像

LinkedList

LinkedListArrayList类似都实现了List接口。但这个接口的实现是在他的父类AbstractSequentialList中:

1
2
3
4
5
public abstract class AbstractSequentialList<E> extends AbstractList<E> {
public Iterator<E> iterator() {
return listIterator();
}
}

迭代器模式解决了不同集合(ArrayList ,.LinkedList)统一遍历问题

注意事项

  • 优点
    • 提供一个统一的方法遍历对象,客户不用再考虑聚合的类型,使用一种方法就可以遍历对象了。
    • 隐藏了聚合的内部结构,客户端要遍历聚合的时候只能取到迭代器,而不会知道聚合的具体组成。
    • 提供了一种设计思想,就是一个类应该只有一个引起变化的原因(叫做单一责任原则)。在聚合类中,我们把迭代器分开,就是要把管理对象集合和遍历对象集合的责任分开,这样一来集合改变的话,只影响到聚合对象。而如果遍历方式改变的话,只影响到了迭代器。
    • 当要展示一组相似对象,或者遍历一组相同对象时使用,适合使用迭代器模式
  • 缺点
    • 每个聚合对象都要一个迭代器,会生成多个迭代器不好管理类