描述
定义
提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部表示。别名游标(Cursor)。
类型
对象行为型模式
动机
一个聚合对象,应该提供一种方法来让别人可以访问它的元素,而又不需暴露它的内部结构。此外,针对不同的需要,可能要以不同的方式遍历这个列表。但是即使可以预见到所需的那些遍历操作,你可能也不希望列表的接口中充斥着各种不同遍历的操作。有时还可能需要在同一个表列上同时进行多个遍历。
UML类图
实现
主要角色
- Iterator:迭代器
- 定义访问和遍历元素的接口。
- ConcreteIterator:具体迭代器
- 实现迭代器接口。
- 对该聚合遍历时跟踪当前位置。
- Aggregate:聚合
- 定义创建相应迭代器对象的接口。
- ConcreteAggregate:具体聚合
- 实现创建相应迭代器的接口,该操作返回ConcreteIterator的一个适当的实例。
- Client:客户类
- 创建具体聚合对象,并通过聚合对象获取迭代器接口,然后遍历聚合对象。
示例
-
Iterator:迭代器
interface Iterator<T> { boolean hasNext(); T next(); }
-
ConcreteIterator:具体迭代器
public class ConcreteIterator<T> implements Iterator<T> { private List<T> list = new ArrayList<>(); private int cursor = 0; public ConcreteIterator(List list){ this.list = list; } @Override public boolean hasNext() { return cursor != list.size(); } @Override public T next() { T obj = null; if (this.hasNext()) { obj = this.list.get(cursor++); } return obj; } }
-
Aggregate:聚合
public interface Aggregate<T> { void add(T obj); void remove(T obj); Iterator<T> createIterator(); }
-
ConcreteAggregate:具体聚合
public class ConcreteAggregate<T> implements Aggregate<T> { private List<T> list = new ArrayList<>(); @Override public void add(T obj) { list.add(obj); } @Override public void remove(T obj) { list.remove(obj); } @Override public Iterator<T> createIterator() { return new ConcreteIterator<>(list); } }
-
Client:发起请求的客户类
public class Client { public static void main(String[] args) { Aggregate<String> agg = new ConcreteAggregate<>(); agg.add("wang"); agg.add("zhao"); agg.add("li"); Iterator<String> itr = agg.iterator(); while (itr.hasNext()) { System.out.println(itr.next()); } }
适用场景
- 访问一个聚合对象的内容而不暴露它的内部表示。
- 为聚合对象提供多种遍历方式。
- 为遍历不同的聚合结构提供一个统一的接口。
优点
- 支持以不同的方式遍历一个聚合。复杂的聚合可用多种方式进行遍历。你也可以自己定义迭代器的子类以支持新的遍历。
- 简化了聚合的接口。有了迭代器的遍历接口,聚合本身就不再需要类似的遍历接口了。
- 在同一个聚合上可以同时有多个遍历。每个迭代器保持它自己的遍历状态。因此你可以同时进行多个遍历。
- 增加新的聚合类和迭代器类都很方便,无须修改原有代码。
- 封装性好,用户只需要得到迭代器就可以遍历,而对于遍历算法则不用去关心。
缺点
- 增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。
相关模式
- Composite:迭代器常被应用到像复合这样的递归结构上。
- Factory Method:多态迭代器靠Factory Method来实例化适当的迭代器子类。
- Memento:迭代器可使用一个memento来捕获一个迭代的状态。迭代器在其内部存储memento。