拿到这个话题,首先搞清楚:什么是迭代器?
大家都学过 for-i 循环,for-i循环的本质就是 通过i++ 或者 i-- ,以实现 从数据的一端 一个一个地遍历数据元素,直到另一端的最后一个元素,将这里 i 的通用作用 抽象化后形成的设计,在设计中就可以叫做迭代器 Iterator;Iterate 在英语中有 "重复说,重复做" 的意思,如:
we iterate through it with foreach.
我们重复做它,通过foreach。(倒过来读也行,我从不求完美。)
Iterator模式的主要作用就是在数据集合中按照顺序一个一个地遍历集合,我们常说的迭代器,就是这个Iterator;假设我们现在需要做一个容器,底层可以使用链表,也可以使用数组,或者映射,或者其他类型,Anyhow 无论如何,肯定都需要为用户设计一些存取,访问遍历等基本操作。
在程序设计中,由于底部容器集合的底层实现不同,各自不同的遍历方式,只有容器它自己知道它自己应该如何去遍历,我们无法将这些不同的容器,限制在某一种特定的遍历方式上,对于这种困境,我们就需要做一个统一存取的迭代器接口,让用户不用关系这些容器因为底层原因而造成有各种花里胡哨的的遍历实现,方便用户。
Iterator 迭代器模式,就是一个专门提供给用户做容器元素访问迭代需求的设计模式。它的优点:
- 避免了将不同底层的容器遍历访问限制死在某一种实现上的困境。
- 不用暴露内部结构给用户,增加用户的易用性。
至于,容器自己怎么遍历,只有容器它自己知道,所以,为了方便用户,我们就要求:让每个容器,自己提供它的迭代器接口,我们用户不用关心它的实现,用就好了。
迭代器接口代码:
/**
* 遍历集合容器的接口。
*/
public interface Iterator {
boolean hasNext();//是否有下一个元素。
Object next(); //获取元素,并指向下一个元素。
}
因此我们要求,凡是你觉得你自己是一个集合的类,麻烦您给我们用户提供一个获取迭代器的接口。
/**
* 表示集合的接口。
*/
public interface AggregateCollection {
/**
* 为用户设计的,提供迭代器的方法。
* @return 返回统一的迭代器。
*/
Iterator iterator();
}
好了,集合容器 主角上场了。
/**
* 表示容器集合类
* 根据约定,但凡 你觉得你自己要实现一个集合容器,你就需要实现 AggregateCollection 接口。
* 以提供给用户获取迭代器的方法 iterator()
*/
public class Container implements AggregateCollection {
private Element[] elements;
private int size = 0;
//根据 默认的最大容量capacity 初始化 容器
public Container(int maxCapacity) {
this.elements = new Element[maxCapacity];
}
//访问容器中每个索引位置的元素。
public Element getElementAt(int index) {
return elements[index];
}
//Container有效元素,size 的维护机制:每次添加一个元素,元素总数cursor 要 + 1
public void appendElement(Element element) {
this.elements[size] = element;
size++;
}
//获取有效元素的个数。
public int getSize() {
return size;
}
@Override
public Iterator iterator() {
return new ContainerIterator(this);
}
}
这里提供属于容器的基础方法。为了弱化类之间的耦合,关于如何遍历的内容,专门提取到下面设计的ContainerIterator类中。
/**
* 容器实现遍历的类。
*/
public class ContainerIterator implements Iterator {
// 引入容器对象,因为next和hashNext方法,该如何实现,只有container自己知道
private Container container;
private int index;
//初始化容器迭代器。
public ContainerIterator(Container container){
this.container = container;
this.index = 0;
}
@Override
public boolean hasNext() {
return index < container.getSize();
}
@Override
public Object next() {
return container.getElementAt(index++);
}
}
容器中的基本元素对象类
/**
* 容器中的元素对象,加个名字,好遍历显示。
*/
public class Element {
private String name;
public Element(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
好了,利用我们的迭代器的设计思想,程序基本已经设计完毕,通过程序测试一下,看看能否达到用户的预期:
站在用户的角度,至于你的集合容器底层如何具体实现,我不管。
凡是你设计的是一个Collection集合容器,你就要给我提供iterate方法,
用户只要拿到你的iterator,
使用的hashNext方法和next方法遍历到你容器中的所有元素。
public class Main {
public static void main(String[] args) {
//集合容器Container 中 包含了 iterator 的功能。
Container container = new Container(6);
container.appendElement(new Element("Java"));
container.appendElement(new Element("PHP"));
container.appendElement(new Element("Javascript"));
container.appendElement(new Element("Golang"));
container.appendElement(new Element("CPP"));
container.appendElement(new Element("Ruby"));
Iterator it = container.iterator();
while (it.hasNext()){
Element element = (Element) it.next();
System.out.println(element.getName());
}
}
}
console 控制台输出:
Java
PHP
Javascript
Golang
CPP
Ruby
满足需求,OK, that's all !加油,GoGo !