为什么要使用迭代模式?相较于数组这样简单的数据容器,有时候我们会需要遍历,操作一些更复杂的数据容器,像ArrayList,HashMap等。那么在遍历或操作这些数据容器时,可能会遇到这样的情况:
一.迭代方式没有改变,但是数据容器变了。
二.数据容器没有改变,但是迭代逻辑变了。
问题是,我们不希望改变客户端代码,那么就只有将可能变化的内容抽象化,让客户端去操作抽象接口。这也是“开闭”原则中所说的,需要将项目中可能发生变化的部分封装起来。这样的话,客户端不需要知道所操作的集合具体是什么类型的,当需要换一种迭代方式时,只需要引入一个新的迭代子对象即可。
这里还有一个宽接口和窄接口的概念。宽接口就是只集合对象对其开放了修改元素的方法的接口,与之相对的没有开放修改的就是窄接口了。可能这么说有点抽象,先列举一下这里有的角色吧:
抽象迭代器(Iterator),定义了遍历集合对象所需的方法
具体迭代器(ConcreteIterator),实现了抽象迭代器,并保持当前的游标位置。
抽象集合类(Aggregate或Collection),给出了创建迭代器的接口方法,如Java中Collection接口中的iterator()
具体集合类(如ArrayList),实现了得到具体迭代器的方法,注意在这里得到具体迭代器是为了使这个迭代器能够调用集合元素的操作方法(添/删),这就是上面说的宽接口。
客户端:持有集合和迭代器的引用,可以使用迭代器的迭代接口进行元素的遍历,也可以通过迭代器来操作集合元素。
/**
* 抽象迭代器接口
* @author wly
*
*/
public interface AbstractIterator {
boolean hasNext();
Object next();
void addItem(Object o); //操作数据容器方法
}
/**
* 抽象数据容器接口
* @author wly
*
*/
public interface AbstractCollection {
int size();
void add(Object o);
AbstractIterator iterator(); //得到迭代器引用
}
package Iterator;
public class ConcreteCollection implements AbstractCollection {
int INIT_LENGTH = 10; //容器初始容量
Object[] objects = new Object[10];
int filledNum = 0; //表示当前容器填充量
@Override
public int size() {
return filledNum;
}
@Override
public void add(Object o) {
if(!(size() < objects.length)) {
Object[] objects2 = new Object[objects.length + INIT_LENGTH];
System.arraycopy(objects, 0, objects2, 0, filledNum);
}
objects[filledNum + 1] = o;
filledNum ++;
}
@Override
public AbstractIterator iterator() {
return new ConcreteIterateA();
}
/**
* 具体迭代器类一
*/
public class ConcreteIterateA implements AbstractIterator {
int cursor = 0;
@Override
public boolean hasNext() {
if(!(cursor >= size())) {
return true;
} else {
return false;
}
}
/**
* 操作容器数据
*/
public void addItem(Object o) {
if(o instanceof String) {
String s = (String)o;
add("A__" + o.toString());
}
}
@Override
public Object next() {
cursor ++;
return objects[cursor];
}
}
/**
* 具体迭代器类二,
* 实现了Iterator接口并保持迭代过程中的游标位置,使用内部类的形式是具体集合类对具体迭代子对象开放的
* @author wly
*
*/
public class ConcreteIterateB implements AbstractIterator {
int cursor = 0;
@Override
public boolean hasNext() {
if(!(cursor >= size())) {
return true;
} else {
return false;
}
}
/**
* 操作容器数据
*/
public void addItem(Object o) {
if(o instanceof String) {
String s = (String)o;
add("B__" + o.toString());
}
}
@Override
public Object next() {
cursor ++;
return objects[cursor];
}
}
}
/**
* 客户端
* @author wly
*
*/
public class Client {
public static void main(String[] args) {
ConcreteCollection collection = new ConcreteCollection();
AbstractIterator iterator = (AbstractIterator)collection.iterator();
iterator.addItem("A");
iterator.addItem("B");
iterator.addItem("C");
while(iterator.hasNext()) {
System.out.println(iterator.next().toString());
}
}
}
输出:A__A
A__B
A__C
当把ConcreteCollection中的iterator()中的返回值改成 new ConcreteIterateB()时,输出:
B__A
B__B
B__C
同样的,我们还可以随时替换迭代器的遍历方法。