「设计模式」迭代器模式
一、概述
迭代器模式(Iterator Pattern)提供一种方法顺序访问一个聚合对象中的各种元素,而又不暴露该对象的内部表示。这种类型的设计模式属于行为型模式。
JDK中的集合类型,例如:List,Set,Map,他们的具体子类几乎都实现了迭代器模式。这样的好处就是,我们可以使用迭代器模式直接遍历内部对象,而不比考虑这个集合的类型是List还是Set还是Map。
迭代器模式的4种角色
(1)抽象聚合(Aggregate)角色:定义存储、添加、删除聚合对象以及创建迭代器对象的接口。
(2)具体聚合(ConcreteAggregate)角色:实现抽象聚合类,返回一个具体迭代器的实例。
(3)抽象迭代器(Iterator)角色:定义访问和遍历聚合元素的接口,通常包含 hasNext()、first()、next() 等方法。
(4)具体迭代器(Concretelterator)角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。
二、优缺点
优点:
- 支持不同方式遍历一个聚合对象,在同一个聚合上可以有多个遍历。
- 简化了聚合类。由于引入了迭代器,在原有的聚合对象中不需要再自行提供数据遍历等方法。
- 在迭代器模式中,由于引入了抽象层,增加新的聚合类和迭代器类都很方便,无须修改原有代码。
缺点:
- 在某些情况下,可能比直接遍历效率低。
- 由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。
三、实现方式
迭代器模式不再自己举例实现了,因为在JDK中java.util.Iterator就是最完美的实例,下面以ArrayList源码为例。
遍历List的几种方式
public class Client {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("s1");
list.add("s2");
list.add("s3");
/**
* 第一种遍历方式:for循环
*/
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
/**
* 第二种遍历方式:foreach循环
* 底层是基于迭代器来实现的
*/
for (String name : list) {
System.out.println(name);
}
/**
* 第三种遍历方式:迭代器遍历
*/
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
抽象迭代器(Iterator)
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());
}
}
具体迭代器实现(Itr)
private class Itr implements Iterator<E> {
int cursor;
int lastRet;
int expectedModCount;
private Itr() {
this.lastRet = -1;
this.expectedModCount = ArrayList.this.modCount;
}
public boolean hasNext() {
return this.cursor != ArrayList.this.size;
}
public E next() {
this.checkForComodification();
int var1 = this.cursor;
if (var1 >= ArrayList.this.size) {
throw new NoSuchElementException();
} else {
Object[] var2 = ArrayList.this.elementData;
if (var1 >= var2.length) {
throw new ConcurrentModificationException();
} else {
this.cursor = var1 + 1;
return var2[this.lastRet = var1];
}
}
}
public void remove() {
if (this.lastRet < 0) {
throw new IllegalStateException();
} else {
this.checkForComodification();
try {
ArrayList.this.remove(this.lastRet);
this.cursor = this.lastRet;
this.lastRet = -1;
this.expectedModCount = ArrayList.this.modCount;
} catch (IndexOutOfBoundsException var2) {
throw new ConcurrentModificationException();
}
}
}
public void forEachRemaining(Consumer<? super E> var1) {
Objects.requireNonNull(var1);
int var2 = ArrayList.this.size;
int var3 = this.cursor;
if (var3 < var2) {
Object[] var4 = ArrayList.this.elementData;
if (var3 >= var4.length) {
throw new ConcurrentModificationException();
} else {
while(var3 != var2 && ArrayList.this.modCount == this.expectedModCount) {
var1.accept(var4[var3++]);
}
this.cursor = var3;
this.lastRet = var3 - 1;
this.checkForComodification();
}
}
}
final void checkForComodification() {
if (ArrayList.this.modCount != this.expectedModCount) {
throw new ConcurrentModificationException();
}
}
}
抽象聚合器(List)
public interface List<E> extends Collection<E> {
Iterator<E> iterator();
}
具体聚合类实现(ArrayList)
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
public Iterator<E> iterator() {
return new Itr();
}
}
四、常见应用场景
- 访问一个聚合对象的内容而无须暴露它的内部表示。
- 需要为聚合对象提供多种遍历方式。
- 为遍历不同的聚合结构提供一个统一的接口。
转载自:https://juejin.cn/post/7145450262079995941