迭代器模式
一、定义
迭代器(Iterator Pattern)模式的定义:又称为游标模式(Cursor Pattern),它提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。迭代器模式可以为不同容器提供一致的遍历行为,而不用关心容器内容元素组成 结构,迭代器模式是一种对象行为型模式 ;迭代器模式是通过将聚合对象的遍历行为分离出来,抽象成迭代器类来实现的,其目的是在不暴露聚合对象的内部结构的情况下,让外部代码透明地访问聚合的内部数据。现在我们来分析其基本结构与实现方法。
迭代器模式主要包含以下角色。
- 抽象聚合(Aggregate)角色:定义存储、添加、删除聚合对象以及创建迭代器对象的接口。
- 具体聚合(ConcreteAggregate)角色:实现抽象聚合类,返回一个具体迭代器的实例。
- 抽象迭代器(Iterator)角色:定义访问和遍历聚合元素的接口,通常包含 hasNext()、first()、next() 等方法。
- 具体迭代器(Concretelterator)角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。
二、迭代器模式的案例
迭代器模式在我们生活中应用的得也比较广泛,比如物流系统中的传送带,不管传送的是什么物品,都被打包成一个一个的箱子并且有一个统一的二维码。这样我们不需要关心箱子里面是啥,我们在分发时只需要一个一个检查发送的目的地即可。还有将书放到书架中,并将书名按顺序显示而不用关心书的内容。这样说可能大家还是觉得应用场景比较模糊,那么就这样说他的主要应用场景有三大类:
1、访问一个聚合对象的内容而无须暴露它的内部表示。
2、需要为聚合对象提供多种遍历方式。
3、为遍历不同的聚合结构提供一个统一的接口。
其实这种设计模式我们在日常开发中基本不会用到,除非需要定制一个自己实现的数据结构对应的迭代器,否则,开源框架提供的 API 完全够用。
/**抽象容器:Aggregate 接口 * 所要便利的集合的接口。实现了该接口的类将成为一个可以保存多个元素的集合,类似数组。 * Aggregate接口中声明的方法为iterator,作用为生成一个用于遍历的迭代器。 * @param <E> */ public interface Aggregate<E>{ boolean add(E element); boolean remove(E element); public abstract Iterator iterator(); }
/**抽象迭代器:Iterator 接口 *作用为遍历集合中元素,相当于循环语句中的循环变量(for(int i =0 ;i<arr.lenth;i++), * 具体实现一个顺序遍历的迭代器。 * hasNext() 方法判断是否存在下一个,next()方法获取下一个元素。 * next方法在获取元素的同时,要将计数器向下一个元素的计数加一。获取的是当前元素,并指向下一个元素。 */ public interface Iterator { public abstract boolean hasNext(); public abstract Object next(); }
public class Book { private String name ; public Book(String name){ this.name=name; } public String getName(){ return name; } }
/** * 具体聚合(ConcreteAggregate) * 实现Aggregate接口。实现了Aggregate接口的iterator方法。 */ public class BookShelf implements Aggregate { private List<Book> books; public BookShelf() { this.books = new ArrayList<Book>(); } public Book getBookAt(int index) { return books.get(index); } @Override public boolean add(Object element) { books.add((Book) element); return true; } public int getLength() { return books.size(); } @Override public boolean remove(Object element) { return false; } /** * 方法返回了遍历书架时要用的BookShelfIterator类作为书架的迭代器。当外部要遍历书架时会调用该方法。 * @return */ @Override public Iterator iterator() { return new BookShelfIterator(this); } }
public class BookShelfIterator implements Iterator { private BookShelf bookShelf; private int index; public BookShelfIterator(BookShelf bookShelf) { this.bookShelf = bookShelf; this.index = 0; } public boolean hasNext() { if (index < bookShelf.getLength()) { return true; } else { return false; } } public Object next() { Book book = bookShelf.getBookAt(index); index++; return book; } }
public class Test { public static void main(String[] args) { BookShelf bookShelf = new BookShelf(); bookShelf.add(new Book("A")); bookShelf.add(new Book("B")); bookShelf.add(new Book("C")); bookShelf.add(new Book("D")); Iterator it = bookShelf.iterator(); while (it.hasNext()) { Book book = (Book) it.next(); System.out.println(book.getName()); } } }
Iterator模式中各角色的作用
Iterator(迭代器)
该角色责任定义按顺序逐个遍历元素的接口。程序中,由Iterator接口扮演,定义了hasNext和next两个方法。
Concretelterator(具体的迭代器)
该角色负责实现Iterator角色所定义的接口.该角色包含了遍历集合所必须的信息。
Aggregate(集合)
该角色负责定义创建Iterator角色的接口。这个接口是一个方法会创建出一个,按照顺序访问保存在我内部元素的人。
ConcreteAggregate(具体集合)
该角色负责实现Aggregate角色所定义的接口。他会创建出具体的Iterator角色,也就是ConcreteIterator,也就是实例中的BookShelf。
三、总结
优点:
- 多态迭代:为不同的聚合结构提供一致的遍历接口,即一个迭代接口可以访问不同的集合对象;
- 简化集合对象接口:迭代器模式将集合对象本身应该提供的元素迭代接口抽取到了迭代器中,使集合对象无须关心具体迭代行为;
- 元素迭代功能多样化:每个集合对象都可以提供一个或多个不同的迭代器,使的同种元索聚合结构可以有不同的迭代行为;
- 解耦迭代与集合:迭代器模式封装了具体的迭代算法,迭代算法的变化,不会影响到集合对象的架构
缺点:
- 对于比较简单的遍历(像数组或者有序列表),使用迭代器方式遍历较为繁琐。
- 在日常开发当中,我们几乎不会自己写迭代器。除非我们需要定制一个自己实现的数据结构对应的迭代器,不然常规的API足够用了