1. 迭代器模式概念
迭代器模式可能是JAVA中最广为人知的模式之一,JAVA程序员在使用集合时,并不需要关注其类型是List、Set还是其他的,因为它们的遍历都可以通过迭代器来完成。迭代器模式在客户访问类和聚合类之间插入,分离了聚合对象与其遍历行为,对客户也隐藏了其内部细节,满足单一职责原则和开闭原则。
迭代器模式优点:
- 访问一个聚合对象的内容而无须暴露它的内部表示。
- 遍历任务交由迭代器完成,这简化了聚合类。
- 增加新的聚合类和迭代器类都很方便,无须修改原有代码。
迭代器模式缺点:
- 增加了类的个数,这在一定程度上增加了系统的复杂性。
迭代器模式类图如下:
- 抽象聚合(Aggregate):也叫抽象容器,定义存储、添加、删除聚合对象以及创建迭代器对象的接口。
- 具体聚合(ConcreteAggregate):也叫具体容器,实现内部不同结构,返回一个迭代器实例。
- 抽象迭代器(Iterator):定义访问和遍历聚合元素的接口。
- 具体迭代器(ConcreteIterator):实现抽象迭代器接口中的方法,完成对聚合对象的遍历,记录遍历的当前位置。
2. 迭代器模式案例
通过迭代器模式实现一个简单的ArrayList,功能包括:添加元素、删除元素、获取元素、遍历元素、获取元素个数。
2.1 抽象迭代器
新建抽象迭代器接口定义迭代器行为,接口名称为Iterator,内容如下:
public interface Iterator<T> {
/**
* 是否有下一个元素
*/
Boolean hasNext();
/**
* 返回下一个元素
*/
T next();
}
2.2 抽象聚合
新建抽象聚合接口用来定义集合的行为,接口名称为Aggregate,内容如下:
public interface Aggregate<T> {
/**
* 添加元素
* @param item 元素
*/
void addItem(T item);
/**
* 删除元素
* @param item 元素
* @return
*/
void remove(T item);
/**
* 获取元素
*/
T getItem(Integer index);
/**
* 获取元素总个数
*/
Integer size();
/**
* 获取迭代器
*/
Iterator<T> iterator();
}
2.3 具体迭代器
新建具体迭代器类实现抽象迭代器,类名为ConcreteIterator,内容如下:
public class ConcreteIterator<T> implements Iterator<T> {
/**
* 聚合对象
*/
private Aggregate aggregate;
/**
* 游动的索引指针
*/
private Integer position;
public ConcreteIterator(Aggregate aggregate){
this.aggregate = aggregate;
position = 0;
}
@Override
public Boolean hasNext() {
// 当索引指针没有游动到最后表示还有元素可以遍历
return position < aggregate.size() ;
}
@Override
public T next() {
if (hasNext()) {
// 返回索引指针处的元素
return (T) aggregate.getItem(position++);
}
return null;
}
}
2.4 具体聚合
新建具体聚合类实现抽象聚合,类名称为ConcreteAggregate,内容如下:
public class ConcreteAggregate<T> implements Aggregate<T> {
/**
* 数组容器初始大小
*/
public static final Integer INIT_SIZE = 10;
/**
* 元素个数
*/
private Integer size;
/**
* 实际容器
*/
private Object[] array;
public ConcreteAggregate(){
array = new Object[INIT_SIZE];
size = 0;
}
@Override
public void addItem(T item) {
if (size < array.length){
// 容量满足
array[size++] = item;
} else {
// 容量不够,需要扩容
Object[] newArray = new Object[size + size / 2];
System.arraycopy(array, 0, newArray, 0, size);
newArray[size++] = item;
array = newArray;
}
}
@Override
public void remove(T item) {
for (int index = 0; index < array.length; index++) {
if (array[index].equals(item)){
Object[] newArray = new Object[size - 1];
// 复制删除元素位置前的元素
System.arraycopy(array, 0, newArray, 0, index);
// 复制删除元素位置后的元素
System.arraycopy(array, index + 1, newArray, index, size - index - 1);
array = newArray;
size -= 1;
break;
}
}
}
@Override
public T getItem(Integer index) {
return (T) array[index];
}
@Override
public Integer size() {
return size;
}
@Override
public Iterator<T> iterator() {
return new ConcreteIterator<>(this);
}
}
2.5 客户端
新建客户端测试容器功能和迭代功能,内容如下:
public class Client {
public static void main(String[] args) {
// 创建一个自定义容器
Aggregate<String> aggregate = new ConcreteAggregate<>();
// 给容器添加20个元素
for (int index = 0; index < 20; index++) {
aggregate.addItem("Hello World " + index);
}
System.out.println("删除前的size = " + aggregate.size());
// 移除容器中的某个元素
aggregate.remove("Hello World 3");
System.out.println("删除后的size = " + aggregate.size());
// 获取迭代器进行迭代输出
Iterator<String> iterator = aggregate.iterator();
int i = 0;
while (iterator.hasNext()){
System.out.println(String.format("item[%d] = %s", ++i, iterator.next()));
}
}
}
3. 迭代器模式应用
如今,迭代器在大多数编程语言中都很流行,它可能是JAVA中使用最广泛的集合包,当使用循环遍历集合时,它也在语言级别实现:
for (String item : list) {
System.out.println("item = " + item);
}
在JAVA语言的ArrayList中有如下结构:
- Collection是JAVA集合类的顶级接口,里面定义了获取元素个数、获取迭代器、添加元素、移除元素等方法。
- Iterable是可迭代性的标志,该接口定义了获取迭代器的方法,迭代器的接口是Iterator,定义了hasNext和next方法。
- ArrayList是具体的聚合类,继承了AbstractList抽象类,在这个抽象类中使用内部类Itr来实现迭代器接口充当具体迭代器。