一、概述
迭代器(Iterator)模式,又叫做游标(Cursor)模式。GOF给出的定义为:提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节。
该模式在客户与容器之间加入了迭代器角色,这样就可以很好的避免容器内部细节的暴露,而且也使得设计符号“单一职责原则”。在迭代器模式中,具体迭代器角色和具体容器角色是耦合在一起的——遍历算法是与容器的内部细节紧密相关的。为了使客户程序从与具体迭代器角色耦合的困境中脱离出来,避免具体迭代器角色的更换给客户程序带来的修改,迭代器模式抽象了具体迭代器角色,使得客户程序更具一般性和重用性。
二、结构
迭代器角色(Iterator):迭代器角色负责定义访问和遍历元素的方法接口,如hasNext()、next()等;
具体迭代器角色(ConcreteIterator):具体迭代器角色要实现迭代器中所定义的访问方法,并要记录遍历中的当前位置,包含对容器角色的引用,便于操纵容器中的各个元素对象;
容器角色(Container):提供创建具体迭代器角色的接口,可以包含操纵具体容器中的集合对象,如追加元素、获取元素数目、获取指定位置的元素灯方法接口;
具体容器角色(ConcreteContainer):实现容器角色中所定义的接口方法,并包含存储元素的容器对象,如数组、链表等。
三、示例程序
优点:1)简化了对象集合的遍历方式,支持以不同的方式遍历一个容器角色。根据实现方式的不同,效果上会有差别。比如说对有序列表,我们可以根据需要提供正序遍历,倒序遍历两种迭代器,用户用起来只需要得到我们实现好的迭代器,就可以方便的对集合进行遍历了;2)封装性良好,用户只需要得到迭代器就可以遍历,而对于遍历算法则不用去关心;3)对同一个容器对象,可以同时进行多个遍历。因为遍历状态是保存在每一个迭代器对象中的;4)使用迭代器访问一个容器对象的内容而无需暴露它的内部表示。5)为遍历不同的容器结构提供一个统一的接口。
缺点:1)对于比较简单的遍历(像数组或者有序列表),使用迭代器方式遍历较为繁琐,大家可能都有感觉,像ArrayList,我们宁可愿意使用for循环和get方法来遍历集合;2)具体容器角色和具体迭代器角色因为是紧耦合关系,在具体容器中使用内部类将具体迭代器实现是一个很好的做法,方便了具体迭代器直接访问具体容器的所有细节。内部类为私有,既实现类具体迭代器,又使此容器的专用迭代器对外不可见,迫使使用者进行接口编程。
五、适用场景
迭代器模式是与集合共生共死的,一般来说,我们只要实现一个集合,就需要同时提供这个集合的迭代器,就像java中的Collection,List、Set、Map等。假如我们要实现一个这样的新的容器,当然也需要引入迭代器模式,给我们的容器实现一个迭代器。1)访问一个容器对象的内容而无需暴露它的内部表示;2)支持对容器对象的多种遍历;3)为遍历不同的容器结构提供一个统一的接口(多态迭代)。
迭代器(Iterator)模式,又叫做游标(Cursor)模式。GOF给出的定义为:提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节。
该模式在客户与容器之间加入了迭代器角色,这样就可以很好的避免容器内部细节的暴露,而且也使得设计符号“单一职责原则”。在迭代器模式中,具体迭代器角色和具体容器角色是耦合在一起的——遍历算法是与容器的内部细节紧密相关的。为了使客户程序从与具体迭代器角色耦合的困境中脱离出来,避免具体迭代器角色的更换给客户程序带来的修改,迭代器模式抽象了具体迭代器角色,使得客户程序更具一般性和重用性。
二、结构
具体迭代器角色(ConcreteIterator):具体迭代器角色要实现迭代器中所定义的访问方法,并要记录遍历中的当前位置,包含对容器角色的引用,便于操纵容器中的各个元素对象;
容器角色(Container):提供创建具体迭代器角色的接口,可以包含操纵具体容器中的集合对象,如追加元素、获取元素数目、获取指定位置的元素灯方法接口;
具体容器角色(ConcreteContainer):实现容器角色中所定义的接口方法,并包含存储元素的容器对象,如数组、链表等。
三、示例程序
public interface Aggregate {
public void append(Object object);
public int getLength();
public Object getObjectAt(int index);
public Iterator iterator();
}
public class ConcreteAggregate implements Aggregate {
private Object[] objects;
private int last;
public ConcreteAggregate(int maxSize) {
this.objects = new Object[maxSize];
this.last = 0;
}
@Override
public void append(Object object) {
this.objects[last++] = object;
}
@Override
public Object getObjectAt(int index) {
return objects[index];
}
@Override
public int getLength() {
return objects.length;
}
@Override
public Iterator iterator() {
return new ConcreteIterator(this);
}
}
public interface Iterator {
public boolean hasNext();
public Object next();
}
public class ConcreteIterator implements Iterator {
private Aggregate aggregate;
private int index;
public ConcreteIterator(ConcreteAggregate concreteAggregate) {
this.aggregate = concreteAggregate;
this.index = 0;
}
@Override
public boolean hasNext() {
return index < aggregate.getLength();
}
@Override
public Object next() {
Object object = null;
if (this.hasNext()) {
object = aggregate.getObjectAt(index++);
}
return object;
}
}
public class Client {
public static void main(String[] args) {
ConcreteAggregate aggregate = new ConcreteAggregate(4);
aggregate.append("aa");
aggregate.append("bb");
aggregate.append("cc");
aggregate.append("dd");
Iterator itr = aggregate.iterator();
while (itr.hasNext()) {
System.out.println(itr.next());
}
}
}
aa
bb
cc
dd
四、优缺点优点:1)简化了对象集合的遍历方式,支持以不同的方式遍历一个容器角色。根据实现方式的不同,效果上会有差别。比如说对有序列表,我们可以根据需要提供正序遍历,倒序遍历两种迭代器,用户用起来只需要得到我们实现好的迭代器,就可以方便的对集合进行遍历了;2)封装性良好,用户只需要得到迭代器就可以遍历,而对于遍历算法则不用去关心;3)对同一个容器对象,可以同时进行多个遍历。因为遍历状态是保存在每一个迭代器对象中的;4)使用迭代器访问一个容器对象的内容而无需暴露它的内部表示。5)为遍历不同的容器结构提供一个统一的接口。
缺点:1)对于比较简单的遍历(像数组或者有序列表),使用迭代器方式遍历较为繁琐,大家可能都有感觉,像ArrayList,我们宁可愿意使用for循环和get方法来遍历集合;2)具体容器角色和具体迭代器角色因为是紧耦合关系,在具体容器中使用内部类将具体迭代器实现是一个很好的做法,方便了具体迭代器直接访问具体容器的所有细节。内部类为私有,既实现类具体迭代器,又使此容器的专用迭代器对外不可见,迫使使用者进行接口编程。
五、适用场景
迭代器模式是与集合共生共死的,一般来说,我们只要实现一个集合,就需要同时提供这个集合的迭代器,就像java中的Collection,List、Set、Map等。假如我们要实现一个这样的新的容器,当然也需要引入迭代器模式,给我们的容器实现一个迭代器。1)访问一个容器对象的内容而无需暴露它的内部表示;2)支持对容器对象的多种遍历;3)为遍历不同的容器结构提供一个统一的接口(多态迭代)。