一、概述
1、定义
Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.(它提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节。)
2、通用类图
3、基本介绍
- 迭代器模式属于行为型模式,提供一种遍历集合元素的统一接口,用一致的方法遍历集合元素,不需要知道集合对象的底层表示,即不暴露其内部的结构。
二、通用源码
迭代器角色:
迭代器角色负责定义访问和遍历元素的接口,一般包括3个方法,即访问下一个元素next(),元素是否已经访问到底部hasNext(),以及删除当前指向的元素remove()。
//抽象迭代器
public interface Iterator {
//遍历到下一个元素
public Object next();
//是否已经遍历到尾部
public boolean hasNext();
//删除当前指向的元素
public void remove();
}
//具体的迭代器
public class ConcreteIterator implements Iterator {
private Vector vector=new Vector();
//定义当前游标
public int cursor=0;
public ConcreteIterator(Vector vector){
this.vector=vector;
}
//返回下一个元素
@Override
public Object next() {
Object result=null;
if (this.hasNext()){
result=this.vector.get(this.cursor++);
}else {
result=null;
}
return result;
}
//判断是否到达尾部
@Override
public boolean hasNext() {
if (this.cursor==this.vector.size()){
return false;
}else {
return true;
}
}
//删除当前元素
@Override
public void remove() {
this.vector.remove(this.cursor);
}
}
容器角色:
容器角色用于创建具体迭代器角色的接口。
//抽象容器
public interface Aggregate {
//添加元素
public void add(Object o);
//移除元素
public void remove(Object o);
//使用迭代器遍历所有的元素
public Iterator iterator();
}
//具体的容器角色
public class ConcreteAggregate implements Aggregate {
//容纳对象的容器
private Vector vector=new Vector();
@Override
public void add(Object o) {
this.vector.add(o);
}
@Override
public void remove(Object o) {
this.vector.remove(o);
}
@Override
public Iterator iterator() {
return new ConcreteIterator(this.vector);
}
}
客户端调用:
public class Client {
public static void main(String[] args){
//声明容器
Aggregate agg=new ConcreteAggregate();
//产生对象数据放进去
agg.add("aaa");
agg.add("bbb");
agg.add("ccc");
//遍历
Iterator iterator=agg.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
三、迭代器模式的应用
1、优点
- 提供一个统一的方法遍历对象,客户不需要考虑聚合的类型;
- 隐藏了聚合的内部结构,客户端要遍历集合的时候只需要取到迭代器,而不需要知道聚合的具体组成;
- 符合单一职责原则,迭代器模式把对象管理与对象遍历分开,如果集合改变只影响聚合对象;遍历方式改变,只影响迭代器。
2、缺点
- 每个聚合对象都要一个迭代器,会造成迭代器过多不好管理;
3、使用场景
- 如果我们的集合元素是用不同的方式实现的,比如:数组、集合类等,当客户端要遍历这些集合元素的时候就需要使用多种遍历方式,而且还会暴露元素的内部结构,可以考虑使用迭代器模式解决。
四、ArrayList源码应用分析
1、类图分析
Itr
类是ArrayList
的内部类,充当的是具体的迭代器角色,而List
与ArrayList
是容器的角色。
2、部分源码展示
List接口:
public interface List<E> extends Collection<E> {
Iterator<E> iterator();
}
Iterator接口:
public interface Iterator<E> {
boolean hasNext();
E next();
default void remove() {
throw new UnsupportedOperationException("remove");
}
}
ArrayList类和Itr类:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
public Iterator<E> iterator() {
return new Itr();
}
//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;
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
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
// update once at end of iteration to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
}