Iterator design pattern
迭代器模式的概念、迭代器模式的结构、迭代器模式的优缺点、迭代器模式的使用场景、迭代器模式的实现示例、迭代器模式的源码分析
1、迭代器模式的概念
迭代器模式,即提供一种方法来顺序访问聚合对象内的元素,而不暴露聚合对象的内部数据结构。即将聚合对象的数据结构和遍历分开,或者说将聚合对象元素存储与遍历分开。
2、迭代器模式的结构
- 抽象迭代器:定义遍历聚合对象内元素的行为。
- 具体迭代器:实现抽象迭代器,实现其定义的遍历聚合对象内元素的行为。
- 抽象聚合:即抽象容器,定义向容器内添加元素、移除元素、获取元素、获取迭代器实例的行为。
- 具体聚合:即具体容器,实现抽象聚合,实现其定义的添加元素、获取元素、移除元素、获取迭代器实例的行为。
3、迭代器模式的优缺点
- 优点:
- 迭代器的存在简化了聚合类。
- 支持以不同的方式遍历聚合对象,且在同一个聚合对象上可遍历多次。
- 新增聚合类和其迭代器很方便,无需修改原有代码,即满足开闭原则。
- 缺点:
- 聚合类和迭代器成对增加,一定程度上增加了系统的复杂性。
4、迭代器模式的使用场景
- 当需要为聚合对象提供多种遍历方式时。
- 当需要为遍历不同的聚合结构提供一个统一的接口时。
- 当需要访问一个聚合对象内的元素而无需暴露聚合对象的数据结构时。
5、迭代器模式的实现示例
抽象迭代器:
public interface Iterator<E> {
/**
* 是否有下一个元素
* @return
*/
boolean hasNext();
/**
* 获取下一个元素
* @return
*/
E next();
}
抽象聚合:
public interface Container<E> {
/**
* 添加元素
* @param e
*/
void add(E e);
/**
* 获取元素
* @param index
* @return
*/
E get(Integer index);
/**
* 移除元素
* @param e
*/
void remove(E e);
/**
* 获取迭代器实例
* @return
*/
Iterator<E> getIterator();
}
具体聚合:
public class OneContainer<E> implements Container<E> {
protected List<E> elements;
public OneContainer() {
this.elements = new ArrayList<>();
}
@Override
public void add(E e) {
this.elements.add(e);
}
@Override
public E get(Integer index) {
return this.elements.get(index);
}
@Override
public void remove(E e) {
this.elements.remove(e);
}
@Override
public Iterator<E> getIterator() {
return new OneContainerIterator();
}
// 具体迭代器(以内部类方式定义)
private class OneContainerIterator implements Iterator<E> {
private Integer index = -1;
@Override
public boolean hasNext() {
return this.index < elements.size() - 1;
}
@Override
public E next() {
if (hasNext()) {
return get(++index);
} else {
return null;
}
}
}
}
测试:
public class IteratorTest {
public static void main(String[] args) {
OneContainer<String> oneContainer = new OneContainer<>();
oneContainer.add("zed");
oneContainer.add("fizz");
oneContainer.add("ahri");
Iterator<String> iterator = oneContainer.getIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
测试结果:
zed
fizz
ahri
6、迭代器模式的源码分析
java 中集合接口 Collection< E> 的子实现类,Map<K, V> 接口的子实现类大部分都是用了迭代器模式,被广泛使用。需要注意的是,在 java 中当需要使用迭代器模式时,只需要让我们自定义的聚合类实现 java.util.Iterable 接口,并实现其定义的 iterator() 让其返回一个 java.util.Iterator 接口的子实现类实例即可。
以下示例 List< E> 接口的子实现类 ArrayList< E> 的迭代器实现:
public interface Iterable<T> {
// 返回一个迭代器实例
Iterator<T> iterator();
// foreach
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
// 创建一个分割器
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
}
public interface Iterator<E> {
// 是否存在下一个元素
boolean hasNext();
// 返回下一个元素
E next();
// 移除元素
default void remove() {
throw new UnsupportedOperationException("remove");
}
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
public Iterator<E> iterator() {
return new Itr();
}
// 迭代器
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
// prevent creating a synthetic constructor
Itr() {}
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
@Override
public void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
final int size = ArrayList.this.size;
int i = cursor;
if (i < size) {
final Object[] es = elementData;
if (i >= es.length)
throw new ConcurrentModificationException();
for (; i < size && modCount == expectedModCount; i++)
action.accept(elementAt(es, i));
// update once at end to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
}