目录
what什么是迭代器模式
Gof定义: 提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。
why为什么需要迭代器模式
一个聚合对象, 如列表(list), 应该提供一种方法来让别人可以访问它的元素,而又不需暴露它的内部结构。此外,针对不同的需要,可能要以不同的方式遍历这个列表。但是即使可以预见到所需的那些遍历操作,你可能也不希望列表的接口中充斥着各种不同遍历的操作。有时还可能需要在同一个表列上同时进行多个遍历。
迭代器模式都可帮你解决所有这些问题。这一模式的关键思想是将对列表的访问和遍历 从列表对象中分离出来并放入一个迭代器(Iterator)对象中。迭代器类定义了一个访问该列表元素的接口。迭代器对象负责跟踪当前的元素; 即, 它知道哪些元素已经遍历过了。
将遍历机制与列表对象分离使我们可以定义不同的迭代器来实现不同的遍历策略,而无 需在列表接口中列举它们。例如, 过滤表列迭代器(FilteringIterator)可能只访问那些满足特 定过滤约束条件的元素。
how如何实现迭代器模式
迭代器模式主要包含以下角色。
- 抽象聚合(Aggregate)角色:定义存储、添加、删除聚合对象以及创建迭代器对象的接口。
- 具体聚合(ConcreteAggregate)角色:实现抽象聚合类,返回一个具体迭代器的实例。
- 抽象迭代器(Iterator)角色:定义访问和遍历聚合元素的接口,通常包含 hasNext()、first()、next() 等方法。
- 具体迭代器(Concretelterator)角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。
开源框架经典案例
Mybatis迭代器模式
mybatis有个类是DefulatCursor类,这个类实现了游标Cursor接口,同时也定义了一个成员变量cursorIterator。看源码会发现CursorIterator是DefaultCurosor的一个内部类。源代码如下。
典型的迭代器模式
private class CursorIterator implements Iterator<T> {
T object;
int iteratorIndex;
private CursorIterator() {
this.iteratorIndex = -1;
}
public boolean hasNext() {
if (this.object == null) {
this.object = DefaultCursor.this.fetchNextUsingRowBound();
}
return this.object != null;
}
public T next() {
T next = this.object;
if (next == null) {
next = DefaultCursor.this.fetchNextUsingRowBound();
}
if (next != null) {
this.object = null;
++this.iteratorIndex;
return next;
} else {
throw new NoSuchElementException();
}
}
public void remove() {
throw new UnsupportedOperationException("Cannot remove element from Cursor");
}
}
JDK源码迭代器模式
集合类的迭代器我们用的也多,以 ArrayList
为例,它就是一个collection的具体聚合,其方法 iterator()
便是获取迭代器的方法。
private class Itr implements Iterator<E> {
/**
* Index of element to be returned by subsequent call to next.
*/
int cursor = 0;
/**
* Index of element returned by most recent call to next or
* previous. Reset to -1 if this element is deleted by a call
* to remove.
*/
int lastRet = -1;
/**
* The modCount value that the iterator believes that the backing
* List should have. If this expectation is violated, the iterator
* has detected concurrent modification.
*/
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size();
}
public E next() {
checkForComodification();
try {
int i = cursor;
E next = get(i);
lastRet = i;
cursor = i + 1;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException(e);
}
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
使用场景
- 访问一个聚合对象的内容而无须暴露它的内部表示。
- 需要为聚合对象提供多种遍历方式。
- 为遍历不同的聚合结构提供一个统一的接口。
优缺点对比
优点
- 支持以不同的方式遍历一个聚合对象,迭代器简化了聚合类。
- 在同一个聚合上可以有多个遍历。
- 在迭代器模式中,增加新的聚合类和迭代器类都很方便,无须修改原有代码。
缺点
- 增加了系统的复杂性。