迭代器模式
迭代器模式一般设计用来对一个容器对象进行遍历,通过引入一个迭代器,将容器的存储功能和遍历功能进行分离,容器只有存储功能,遍历功能由迭代器来完成,进行了职责的分离,更加符合单一职责原则。
在使用迭代器模式的过程中,除了功能的分离,还有另一个好处:当一个容器接口有不同的实现的时候,为每一个实现提供了一个统一的遍历接口,这样一方面具体实现不需要对外暴露它的内部结构,另一方面调用方也不用关系实现类内部结构的变化,只要关注它的遍历方法就可以了,这也是解耦的好处。
定义
提供一种方法顺序访问一个聚合对象中的各个元素,而又不用暴露该对象的内部表示。
结构
迭代器模式中包含了容器和迭代器两个方面的层次结构,具体结构如下:
- Iterator抽象迭代器,定义了迭代器的接口和遍历的方法
- ConcreteIterator具体迭代器。迭代器接口的实现类,实现了迭代器中的所有方法
- Aggregate抽象聚合(容器)类。容器接口,定义了存储和获取迭代器的方法
- ConcreteAggregate具体聚合(容器)类。实现了容器接口,实现了具体存储和获取迭代器的方法
实例
参照上面类图,编写一个简单的容器和迭代器的实现。在设计迭代器接口的时候,接口方法的设计特别重要,一方面要考虑方法的适用性,能够提供各种重要的遍历方案,另一方面又不能有太多的抽象方法。在下面的例子中,只有简单的next()和hasNext()方法。
package iterator;
class Fruit {
public Fruit(String name, String color) {
super();
this.name = name;
this.color = color;
}
private String name;
private String color;
@Override
public String toString() {
return "Fruit [name=" + name + ", color=" + color + "]";
}
}
package iterator;
interface FruitIterator {
boolean hasNext();
Fruit next();
}
package iterator;
public interface FruitAggregate {
void addFruit(Fruit fruit);
FruitIterator iterator();
}
package iterator;
import java.util.List;
public class FruitIteratorList implements FruitIterator {
private List<Fruit> fruitList;
private int now;
public FruitIteratorList(FruitAggregateList fruitAggregateList) {
this.fruitList = fruitAggregateList.fruitList;
}
@Override
public boolean hasNext() {
return now < fruitList.size();
}
@Override
public Fruit next() {
return fruitList.get(now++);
}
}
package iterator;
import java.util.List;
public class FruitIteratorList implements FruitIterator {
private List<Fruit> fruitList;
private int now;
public FruitIteratorList(FruitAggregateList fruitAggregateList) {
this.fruitList = fruitAggregateList.fruitList;
}
@Override
public boolean hasNext() {
return now < fruitList.size();
}
@Override
public Fruit next() {
return fruitList.get(now++);
}
}
package iterator;
public class Test {
public static void main(String[] args) {
Fruit apple = new Fruit("苹果", "红色");
Fruit pear = new Fruit("梨", "青色");
FruitAggregate fruits = new FruitAggregateList();
fruits.addFruit(apple);
fruits.addFruit(pear);
FruitIterator iterator = fruits.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
应用
关于迭代器模式,最常见的便是java的集合部分。因为具体迭代器的实现跟关联的具体容器类有关,因此不同实现的容器类应该有不同的迭代器。比如上面的实例中,FruitIteratorList是通过List实现自己的存储功能的,那么它的迭代器必定是在List的基础上实现的,迭代器的方法都与List中的方法有关。因此,不同的容器有不同的迭代器实现。
Java中,是通过内部类来实现迭代器的。无论是存储结构还是迭代器的实现,不同的Collection实现类内部都是不一样的,而且这些都是不需要对外暴露的内容,因此我们只需要知道迭代器有哪些方法,并且怎么获取迭代器就可以了。
public interface List<E> extends Collection<E> {
...
Iterator<E> iterator();
}
public class ArrayList<E> extends AbstractList<E> {
...
public Iterator<E> iterator() {
return new Itr();
}
...
private class Itr implements Iterator<E> {
...
}
..
}
优缺点
优点
- 将容器类的存储功能和遍历功能相分离
- 不需要对外暴露容器内部具体的实现
- 提供统一的迭代器方法,对于容器的不同实现提供了规范
- 引入抽象设计,对于新的容器只需要引入新的迭代器,符合开闭原则
缺点
- 增加新的容器就需要增加新的迭代器,增加了代码的复杂性
- 抽象迭代器设计比较麻烦
适用场景
- 提供了一个容器对象但是无须了解内部实现
- 容器具有对重实现方式或者容器需要多种遍历方式
- 为不同的容器结构提供一个遍历的统一方法