1.定义
迭代器模式,属于行为型模式。其目的是提供一种顺序访问访问聚合对象(集合)中的各种元素,而又不暴露该对象的内部表示。
迭代可以理解为就是对集合对象内部元素的遍历访问,一般情况下可以通过直接访问这个对象(集合)或者获取对象元素进行遍历,这是传统的做法。迭代器提供了一种更优雅、更灵活的遍历方式,使得外部访问对象(集合)的元素更为简单,单一。
提到迭代器,一般会想起Java集合框架中的迭代器Iterator,是的,他们的迭代器就是迭代器模式的实现,其内部原理很简单,每个集合内部都会以内部类的方式维护一个专属的迭代器,迭代器是可以访问集合对象内部的元素的,根据集合的不同特性对应的迭代器实现也不同,迭代器的职责范围仅仅属于当前的集合,然后对所有的迭代器通过接口的方式向外暴露,供外部调用。
譬如以下代码:
List<String> arrayList = new ArrayList<>();
Iterator<String> it1 = arrayList.iterator();
LinkedList<Object> linkedList = new LinkedList<>();
Iterator<Object> it2 = linkedList.iterator();
虽然ArrayList和LinkedList都是返回了迭代器,但是迭代器是集合内部的私有对象,所谓私有。两层含义:其一迭代器在集合内部被private修饰 其二迭代器是为当前集合“定制”,只适用于当前数据结构,比如以上的两个迭代器,ArrayList迭代器是基于数组的方式操作元素,而LinkedList迭代器是基于链表的方式操作元素,在外部使用来看,他们似乎并无区别。而从这里也能看出来,迭代器为所有的对象集合统一了访问的方式,但他们的内部实现因集合而异,亦或者可以说是将遍历访问行为从集合中独立出来,更加符合单一职责原则。
迭代器实现可谓相当多
简单贴两个看下
ArrayList迭代器实现(数组):
LinkedList迭代器实现(链表):
通过以上分析,不难发现,迭代器模式总体上就两个角色,对象聚合类和迭代器,细分的话,加上抽象层就是四个
- Aggregate(抽象聚合类):它用于储存和管理元素对象,包含一个方法,返回迭代器实例
- ConcreteAggregate(聚合聚合类):实现了抽象聚合类的方法,返回具体的实例
- Iterator(抽象迭代器):包含了访问聚合对象内部元素的方法,比如是否有下一个元素hasNext,取下一个next,或者可以定义一个previous,向前遍历等等
- ConcreteIterator(具体迭代器):对应具体的聚合对象的迭代器实现,根据实际需求结合聚合对象特征实现
UML:
图片来源:百度图库
2.示例
如果上边您已经完全理解,接下来的简单看看就好,这里给出一个简单实现,供参考
以一个简单Person类,来实现迭代器,首先定义Person抽象层,提供基本的对象访问方法,如add/remove等,其中最重要的是定义一个用于返回迭代器的方法getIterator(),具体实现中应返回对象专属的迭代器实例
/**
* @description: 聚合对象抽象
* @version: 1.0
*/
public interface Person {
void addAll(List<Object> objects);
void add(Object o);
void remove(Object o);
Iterator getIterator();
}
聚合对象实现,这里使用一个list作为存储元素的容器,这个list其实就是迭代器操作的对象
/**
* @description: 聚合对象实现
* @version: 1.0
*/
public class Student implements Person{
private List<Object> elements = new ArrayList<>();
@Override
public void addAll(List<Object> objects) {
elements.addAll(objects);
}
@Override
public void add(Object o) {
elements.add(o);
}
@Override
public void remove(Object o) {
elements.remove(o);
}
@Override
public Iterator getIterator() {
return new PersonIterator(elements);
}
}
迭代器的抽象层,这里简单定义两个方法 一个hasNext 一个 next方法,用于判断是否还有元素以及指针向下偏移获取元素,(这里需要注意的是,next每次调用,偏移+1)
/**
* @description: 迭代器抽象
* @version: 1.0
*/
public interface Iterator<E> {
boolean hasNext();
E next();
}
迭代器的实现,迭代器初始化时必须持有需要访问的元素
/**
* @description: 迭代器实现
* @version: 1.0
*/
public class PersonIterator implements Iterator{
private List<Object> elements = null;
private int index = -1;
public PersonIterator(List<Object> elements) {
this.elements = elements;
}
@Override
public boolean hasNext() {
return index + 1 < elements.size();
}
@Override
public Object next() {
return hasNext() ? elements.get(++index) : null;
}
}
测试:
/**
* @description: test
* @version: 1.0
*/
public class Test {
public static void main(String[] args) {
String[] persons = {"张三","李四","王五","赵大娘","王大爷","马冬梅"};
Person stu = new Student();
stu.addAll(Arrays.asList(persons));
for (Iterator iterator = stu.getIterator();iterator.hasNext();){
Object next = iterator.next();
System.out.println(next);
}
}
}
input:
张三
李四
王五
赵大娘
王大爷
马冬梅
3.总结
迭代器的最重要的优点就是使得聚合对象的职责变得简单,聚合对象不需要再提供遍历自身的方法,取而代之的是迭代器去完成,并且可以提供一种隐藏内部数据、约束元素访问方式的机制,对于客户端透明,扩展方便,符合开闭原则和单一职责原则。缺点自然就是多了迭代器类的设计,如果对象过多,那可能就需要对迭代器进行一些列更高抽象的设计,这会增加一定的设计复杂性。