简述
1)在开发过程中我们都需要对许多数据进行操作,为了保存这些数据我们会把这些数据存放在容器中,待需要使用的时候再从容器中取出来使用。
2)为了我们使用的方便,我们会把容器定义成不同的数据结构,例如:队列、链表、栈,树等,就是为了让我们使用数据方便。
3)使用数据的时候我们就要对这些容器进行遍历,不同的数据结构有不同的遍历方法,甚至相同的数据结构会有多种遍历方法,例如树我们有前序遍历、中序遍历和后续遍历等
4)在编写这个容器的时候我们没有必要把这些遍历方法都写到容器中,这样就模糊了容器的主要功能,容器是用来存储数据的。
5)所以为了方便,我们就把遍历容器的方法抽取出来,形成了迭代器模式。
6)迭代器模式,提供一种遍历容器元素的同一接口,用一致的方法遍历容器元素,不需要知道容器的底层表示,即:不暴露内部结构
原理
1)Iterator:迭代器接口,是系统提供,含义 hasIlext,next,remove
2)ConcreteIterator :具体的容器类
3)Aggregate:一个统一的容器聚合接口,将客户端和具体迭代器解耦
4)Concretelggreage:具体的容器持有对象集合,并提供一个方法,返回一个送代器,该送代器可以正确遍历集合
5)Client:客户端,通过Iterator和Aggregate依赖子类
代码示例
底层是数组的容器
public class ArrayCollege implements College{
/**
* 容器
*/
private Integer[] arr = new Integer[10];
/**
* 元素存放的位置
*/
private int index = 0;
public void add(Integer integer) {
if (index >= arr.length ) {
return;
}
arr[index++] = integer;
}
public void remove(Integer integer) {
// 暂不实现
}
@Override
public Iterator createIterator() {
return new ArrayIterator(this.arr);
}
}
底层是List的容器
public class ListCollege implements College{
private List<Integer> list = new ArrayList<>();
public void add(Integer integer) {
list.add(integer);
}
public void remove(Integer integer) {
// 暂不实现
}
@Override
public Iterator createIterator() {
return new ListIterator(this.list);
}
}
写一个对数组的迭代器
public class ArrayIterator implements Iterator {
/**
* 容器 【迭代器是需要知道容器的底层数据结构的】
*
* 【 通过构造方法传进来】
*/
private Integer[] arr;
/**
* 获取元素的指针
*/
private int index = -1;
public ArrayIterator(Integer[] arr) {
this.arr = arr;
}
@Override
public boolean hasNext() {
if (++index >= arr.length) {
return false;
}
if (arr[index] == null) {
return false;
}
return true;
}
@Override
public Object next() {
return arr[index];
}
}
写一个对List的迭代器
public class ListIterator implements Iterator {
private List<Integer> list;
private int index = -1;
public ListIterator(List<Integer> list) {
this.list = list;
}
@Override
public boolean hasNext() {
if (++index >= list.size()) {
return false;
}
return true;
}
@Override
public Object next() {
return list.get(index);
}
}
写测试用例
public class Client {
public static void main(String[] args) {
ArrayCollege arrayCollege = new ArrayCollege();
arrayCollege.add(1);
arrayCollege.add(2);
arrayCollege.add(3);
Iterator iterator = arrayCollege.createIterator();
while (iterator.hasNext()) {
Integer next = (Integer) iterator.next();
System.out.println(next);
}
System.out.println("=================================================");
ListCollege listCollege = new ListCollege();
listCollege.add(1);
listCollege.add(2);
listCollege.add(3);
Iterator iterator1 = listCollege.createIterator();
while (iterator1.hasNext()) {
Integer next = (Integer) iterator1.next();
System.out.println(next);
}
}
}
注意事项和细节
优点
1)提供一个统一的方法遍历对象,客户不用再考虑容器的类型,使用一种方法就可以遍历对象了。
2)隐藏了容器的内部结构,客户端要遍历容器的时候只能取到迭代器,而不会知道容器的具体组成。
3)提供了一种设计思想,就是一个类应该只有一个引起变化的原因(叫做单一责任原则)。在容器类中,我们把迭代器分开,就是要把管理对象集合和遍历对象集合的责任分开,这样一来集合改变的话,只影响到容器对象。而如果遍历方式改变的话,只影响到了迭代器。
4)当要展示一组相似对象,或者遍历一组相同对象时使用,适合使用迭代器模式
缺点
每个容器对象都要一个迭代器,会生成多个迭代器不好管理类