迭代子模式可以顺序的访问集合内部的元素而不必知道集合内部表象。
多个对象聚集在一起形成集合的概念,所以集合对象也叫容器,包含 n 多对象的池子一样。集合对象需要提供一些方法,使得可以顺序访问内部对象。集合对象常见的问题分为两类,一是把一种集合对象转换为另外一个集合对象,由于集合对象各自的遍历集合不同,这里就需要修改客户端代码了(违背开闭原则);二是集合本身不变,迭代方法改变,这个时候需要修改集合对象。这两个问题都涉及到需要修改代码,也就违背了开闭原则(能够在不修改代码的情况下对功能进行扩展,开闭原则其实是需要把不变的与易变的进行分割
)。针对这样的问题,在客户端和集合对象之间增加一个迭代子这么一个中间层,使得客户端和集合对象之间由直接变成间接,降低耦合力度。
迭代子模式的类图大概如下所示
Aggregate集合:创建迭代子的接口;
ConcreteAggregate 具体集合:实现迭代子接口;
Iterator 迭代子接口:给出迭代每个元素的接口;
ConcreteIterator 具体迭代子:实现迭代方法。
如果一个集合对象对外提供了修改内部元素的方法,那么这个接口就叫宽接口
;如果不对外提供修改元素的方法,就叫窄接口
,其实这叫法我觉得无所谓,关键是集合类对外提供修改接口,就破坏了集合对象的封装,而此时的迭代子在外部控制元素的迭代,作用相当于一个游标,有个雅称叫游标迭代子
;改良的做法是集合对象对外不提供对元素的修改方法,只对迭代子提供宽接口。
下面使用代码更加形象的说明之。
集合类提供几个方法,第一个是获取迭代子;第二个是获得指定位置的元素了第三是获取集合元素的数量;
public abstract class Aggregate {
public abstract MyIterator iterator();
public abstract Object getElement(int index);
public abstract int size();
}
具体集合类的实现,这里使用一个数组作为静态的内部元素,如果使用动态外部的元素需要改造
public class ConcreteAggregate extends Aggregate{
private String[]arr={"A","B","C"};
@Override
public MyIterator iterator() {
return new ConcreteIterator(this);
}
public Object getElement(int index){
return arr[index];
}
public int size(){
return arr.length;
}
}
抽象迭代子
public interface MyIterator {
//移动到第一个对象
public void first();
//是否最后
public boolean isLast();
//移动下一个
public void next();
//当前对象
public Object current();
}
一个具体的实现
public class ConcreteIterator implements MyIterator{
Aggregate agg;
int size=0;
int index=0;
public ConcreteIterator(Aggregate agg) {
this.agg=agg;
size=agg.size();
}
@Override
public void first() {
index=0;
}
@Override
public boolean isLast() {
return index>=size;
}
@Override
public void next() {
if(index<size){
index++;
}
}
@Override
public Object current() {
return agg.getElement(index);
}
}
来个客户端运行下看看
public class Client {
public static void main(String[] args) {
Aggregate agg=new ConcreteAggregate();
MyIterator iterator = agg.iterator();
//可以把 isLast 和 next 方法整合到一起
while(!iterator.isLast()){
System.out.println(iterator.current());
iterator.next();
}
}
}
可以打印出A、B、C,而且可以新增新的迭代子和新的集合类实现来进行不同的顺序输出。
迭代子模式的意义是使得客户端与迭代子任务分开,使二者各自完成自己的主要工作,在集合对象发生改变或者迭代方法发生变化的时候,有了这个迭代子缓冲地带,我们可以尽量只对迭代子部分进行修改。并不是说客户端自己不可以迭代,只是不够优雅。
迭代子把集合的循环迭代方法进行了处理,集合本身不需要迭代;集合本身可以包含不仅一个的迭代子,根据情况获取不同的迭代子,进行不同的迭代子处理;遍历算法包括迭代子内部,因此迭代子独立于集合。迭代子的缺点是对象总是 Object 的,这个需要显示的强制转换。