什么是迭代器模式
迭代器模式(Iterator),提供一种方法顺序访问一个聚合对象中的各种元素,而又不暴露该对象的内部表示。
Java 开发过程中遍历是常用的。如下边程序
for(int i =0 ;i<arr.length;i++){
System.out.println(arr[i]);
}
角色
Iterator(迭代器)
该角色责任定义按顺序逐个遍历元素的接口。
程序中,由Iterator接口扮演,定义了hasNext和next两个方法。
Concretelterator(具体的迭代器)
该角色负责实现Iterator角色所定义的接口.该角色包含了遍历集合所必须的信息。
Aggregate(集合)
该角色负责定义创建Iterator角色的接口。这个接口是一个方法会创建出一个,按照顺序访问保存在我内部元素的人。
ConcreteAggregate(具体集合)
该角色负责实现Aggregate角色所定义的接口。他会创建出具体的Iterator角色,也就是集合下的ArrayList和LinkedList
优缺点
优点
- 简化了遍历方式,对于对象集合的遍历,还是比较麻烦的,对于数组或者有序列表,我们尚可以通过游标来取得,但用户需要在对集合了解很清楚的前提下,自行遍历对象,但是对于hash表来说,用户遍历起来就比较麻烦了。而引入了迭代器方法后,用户用起来就简单的多了。
- 可以提供多种遍历方式,比如说对有序列表,我们可以根据需要提供正序遍历,倒序遍历两种迭代器,用户用起来只需要得到我们实现好的迭代器,就可以方便的对集合进行遍历了。
- 封装性良好,用户只需要得到迭代器就可以遍历,而对于遍历算法则不用去关心。
缺点
对于比较简单的遍历(像数组或者有序列表),使用迭代器方式遍历较为繁琐,大家可能都有感觉,像ArrayList,我们宁可愿意使用for循环和get方法来遍历集合。
适用场景
迭代器模式是与集合共生共死的,一般来说,我们只要实现一个集合,就需要同时提供这个集合的迭代器,就像java中的Collection,List、Set、Map等,这些集合都有自己的迭代器。假如我们要实现一个这样的新的容器,当然也需要引入迭代器模式,给我们的容器实现一个迭代器。
但是,由于容器与迭代器的关系太密切了,所以大多数语言在实现容器的时候都给提供了迭代器,并且这些语言提供的容器和迭代器在绝大多数情况下就可以满足我们的需要,所以现在需要我们自己去实践迭代器模式的场景还是比较少见的,我们只需要使用语言中已有的容器和迭代器就可以了。
实现
集合接口
public interface Collection_<E> {
void add(E o);
int size();
Iterator_ iterator();
}
迭代器接口
public interface Iterator_<E> { //Element //Type //K //Value V Tank
boolean hasNext();
E next(); //Tank next() Iterator_<Tank> it = ... Tank t = it.next();
}
数组实现
/**
* 相比数组,这个容器不用考虑边界问题,可以动态扩展
*/
class ArrayList_<E> implements Collection_<E> {
E[] objects = (E[])new Object[10];
//objects中下一个空的位置在哪儿,或者说,目前容器中有多少个元素
private int index = 0;
public void add(E o) {
if(index == objects.length) {
E[] newObjects = (E[])new Object[objects.length*2];
System.arraycopy(objects, 0, newObjects, 0, objects.length);
objects = newObjects;
}
objects[index] = o;
index ++;
}
public int size() {
return index;
}
@Override
public Iterator_<E> iterator() {
return new ArrayListIterator();
}
private class ArrayListIterator<E> implements Iterator_<E> {
private int currentIndex = 0;
@Override
public boolean hasNext() {
if(currentIndex >= index) return false;
return true;
}
@Override
public E next() {
E o = (E)objects[currentIndex];
currentIndex ++;
return o;
}
}
}
链表实现
/**
* 相比数组,这个容器不用考虑边界问题,可以动态扩展
*/
class LinkedList_ implements Collection_ {
Node head = null;
Node tail = null;
//目前容器中有多少个元素
private int size = 0;
public void add(Object o) {
Node n = new Node(o);
n.next = null;
if(head == null) {
head = n;
tail = n;
}
tail.next = n;
tail = n;
size++;
}
private class Node {
private Object o;
Node next;
public Node(Object o) {
this.o = o;
}
}
public int size() {
return size;
}
@Override
public Iterator_ iterator() {
return null;
}
}
测试
/**
* v1:构建一个容器,可以添加对象
* v2:用链表来实现一个容器
* v3:添加容器的共同接口,实现容器的替换
* v4:如何对容器遍历呢?
* v4:用一种统一的遍历方式,要求每一个容器都要提供Iterator的实现类
* 作业:实现LinkedList的Iterator
* v6:JDK的容器实现
* v7:实现泛型版本
*/
public class Main {
public static void main(String[] args) {
Collection_<String> list = new ArrayList_<>();
for(int i=0; i<15; i++) {
list.add(new String("s" + i));
}
System.out.println(list.size());
//这个接口的调用方式:
Iterator_<String> it = list.iterator();
while(it.hasNext()) {
String o = it.next();
System.out.println(o);
}
}
}