迭代器模式(ITERATOR),又称游标(Cursor),提供了一种方法,用于顺序访问一个聚合对象中的各个元素,而不需暴露该对象的内部表示,属于对象行为型模式。迭代器模式通过将对聚合对象(通常为列表)的访问和遍历从聚合对象中分离出来并放入一个迭代器对象中,迭代器对象知道如何遍历列表,这样不仅可以简化聚合对象的实现(将遍历操作交给迭代器负责,自己只负责保存),还可以以不同的方式遍历列表。
一、使用场景
1、访问一个聚合对象的内容而无需暴露它的内部表示。
2、支持对聚合对象的多种遍历,比如正向遍历,逆向遍历,JDK的迭代器只实现正向遍历。
3、为遍历不同的聚合结构提供一个统一的接口。对不同的聚合结构只需切换要遍历的对象而不需改变遍历过程的代码。
二、UML图
三、Java实现
package study.patterns.iterator;
import java.util.ArrayList;
import java.util.List;
/**
* 迭代器模式,为遍历聚合结构而生!
* 迭代器模式通常使用工厂方法模式来实例化适当的迭代器子类。
* @author qbg
*/
public class IteratorPattern {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("Java编程思想");
list.add("设计模式");
list.add("编程匠艺");
list.add("重构");
AbstractList<String> books = new ConcreteList<String>(list);
Iterator<String> iterator = books.iterator();
System.out.println("=======正向遍历===========");
while(iterator.hasNext()){
System.out.print(iterator.next()+",");
}
System.out.println("\n=======逆向遍历===========");
while(iterator.hasPrevious()){
System.out.print(iterator.previous()+",");
}
}
}
/**
* 抽象聚合类
* @param <E>
*/
abstract class AbstractList<E>{
protected List<E> elements = new ArrayList<E>();
public AbstractList(List<E> eles){
this.elements = eles;
}
public void add(E e){
elements.add(e);
}
public void remove(E e){
elements.remove(e);
}
public List<E> getAll(){
return elements;
}
/**
* 声明创建迭代器对象的抽象工厂方法
*/
public abstract Iterator<E> iterator();
}
/**
* 具体聚合类,创建基于该聚合类的迭代器
* @param <E>
*/
class ConcreteList<E> extends AbstractList<E>{
public ConcreteList(List<E> eles) {
super(eles);
}
@Override
public Iterator<E> iterator() {
return new ConcreteIterator<E>(this);
}
}
/**
* 遍历器抽象接口,支持泛型
*/
interface Iterator<E>{
/**
* 正向遍历,判断是否有后继节点
*/
public boolean hasNext();
/**
* 游标下移,返回游标越过的元素引用
*/
public E next();
/**
* 逆向遍历,判断是否有前驱节点
*/
public boolean hasPrevious();
/**
* 游标上移,返回游标越过的元素引用
*/
public E previous();
}
/**
* 具体迭代器,用于遍历AbstractList<E>集合.
* 支持正向遍历和逆向遍历
* @param <E>
*/
class ConcreteIterator<E> implements Iterator<E>{
private AbstractList<E> list;//要遍历的集合
private List<E> elements;//集合中的元素
private int cursor_forword;//正向遍历的游标,用于记录正向遍历的位置
private int cursor_backword;//逆向遍历的游标,用于记录逆向遍历的位置
public ConcreteIterator(AbstractList<E> list){
this.list = list;
this.elements = this.list.getAll();//获取集合元素
this.cursor_forword = 0;//设置正向遍历游标初始值
this.cursor_backword = elements.size()-1;//设置逆向遍历游标初始值
}
@Override
public boolean hasNext() {
return cursor_forword < elements.size();
}
@Override
public E next() {
E e = elements.get(cursor_forword);
cursor_forword++;
return e;
}
@Override
public boolean hasPrevious() {
return cursor_backword >= 0;
}
@Override
public E previous() {
E e = elements.get(cursor_backword);
cursor_backword--;
return e;
}
}
运行结果:
=======正向遍历===========
Java编程思想,设计模式,编程匠艺,重构,
=======逆向遍历===========
重构,编程匠艺,设计模式,Java编程思想,
四、模式优缺点
优点:
1、支持以不同的方式遍历一个聚合。想改变遍历方式只需用一个不同的迭代器实例代替原先的实例即可。
2、迭代器简化聚合的接口。有了迭代器的遍历接口,聚合本身就不需要类似的遍历接口了。
3、在同一个聚合上可以有多个遍历。每个迭代器保持它自己的遍历状态,互不影响。
缺点:
1、抽象迭代器的设计比较难以把握,如果前期设计不好,后期改动就会非常大。比如JDK的迭代器只支持正向遍历,如果想实现其他遍历方式只能通过添加辅助类实现。