1.迭代器模式-行为类模式
在面向对象程序设计中,对于集合对象,我们无非关注两点:一是集合内部的数据存储结构,二是遍历集合内部的数据。面向对象的设计原则中有一条是类的单一职责原则,所以要尽可能分解这些职责,用不同的类去承担不同的职责,Iterator模式就是分离集合对象的遍历行为。
2.迭代器模式的角色
(1)迭代器角色Iterator:负责定义访问和遍历元素的接口;
(2)具体迭代器角色 Concrete Iterator:实现迭代器接口,并记录遍历中的当前位置;
(3)容器角色 Aggregate:提供创建具体迭代器角色的接口;
(4)具体容器角色 Concrete Aggregate:实现创建具体迭代器角色的接口,与容器的结构相关。
3.类图
4.迭代器模式的优缺点
优点:简化了遍历方式,对于对象集合的遍历,还是比较麻烦的,对于数组或者有序列表,我们尚可以通过游标来取得,但用户需要在对集合了解很清楚的前提下,自行遍历对象,但是对于hash表来说,用户遍历起来就比较麻烦了。而引入了迭代器方法后,用户用起来就简单的多了。可以提供多种遍历方式,比如说对有序列表,我们可以根据需要提供正序遍历,倒序遍历两种迭代器,用户用起来只需要得到我们实现好的迭代器,就可以方便的对集合进行遍历了。封装性良好,用户只需要得到迭代器就可以遍历,而对于遍历算法则不用去关心。
缺点:对于比较简单的遍历(像数组或者有序列表),使用迭代器方式遍历较为繁琐,大家可能都有感觉,像ArrayList,我们宁可愿意使用for循环和get方法来遍历集合。
5.迭代器模式的实现方式
(1)思考:迭代器角色定义了遍历的接口,由谁来控制迭代?迭代器模式中,由谁来实现遍历算法?
(2)在Java Collection中,提供的具体迭代器角色是定义在容器角色中的内部类,这样保护了容器的封装性。
(3)Java Collection的具体实现:
//迭代器角色,仅仅定义了遍历接口
public interface Iterator {
boolean hasNext();
Object next();
void remove();
}
//容器角色,以List为例,它也是仅仅定义一个接口
//具体容器角色,以实现List接口的ArrayList为例
//具体迭代器角色,以内部类的形式,AbstractList提取公共部分
public abstract class AbstractList extends AbstractCollextion implements List {
//创建具体迭代器角色的工厂方法
public Iterator itrator() {
return new Itr();
}
//作为内部类的具体迭代器角色
private class Itr implements Iterator {
int cursor = 0;
int lastRet = -1;
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size();
}
public Object next() {
checkForComodification();
try {
Object next = get(cursor);
lastRet = cursor++;
return next;
} catch(IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public void remove() {
if (lastRet == -1)
throw new IllegaStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if(lastRet < cursor)
cursor --;
lastRet = -1;
expectedModCount = modCount;
} catch(IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if(modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
}
迭代器的使用,客户端程序要先得到具体容器角色,然后在通过具体容器角色得到具体迭代器角色,这样便可以使用具体迭代器角色来遍历容器了。
4.具体例子-植树
例子:一个山上没有任何树,现在要种植几棵树,然后遍历这些树,给每棵树喷洒不同的农药,从这个例子中可以看到,遍历树就可以用到迭代器模式。
Step 1:做一个迭代器接口,思考为什么要抽象出一个接口?
package model;
//迭代器接口
public interface Iterator {
boolean hasNext();//是否还有下一条数据
Object next();//返回具体的树
}
Step 2:做个容器,即“山”
package model;
//1.要有种树的功能,山的功能和树是一种聚合关系
public class Hall {
Tree[] tree; //聚合关系
private int index; //指向Tree[]的标签
public Hall (int maxNumber) {
tree = new Tree[maxNumber];
index = 0;
}
public void add (Tree tree) {
this.tree[index] = tree;
index++;
}
public Iterator connectIterator () {
return new TreeIterator (this);
}
}
Step 3.树对象
package model;
//树对象
public class Tree {
private String name;
public Tree (String name) {
this.name = name;
}
public String getName () {
return this.name;
}
}
Step 4.具体迭代器类
package model;
//具体迭代器类,和Hall之前也是一种聚合关系
public class TreeIterator implements Iterator {
private int last = 0;
private Hall hall;
//通过构造函数把山和迭代器联系起来
public TreeIterator (Hall hall) {
this.hall = hall;
}
@Override
public boolean hasNext () {
if (last < hall.tree.length)
return true;
else
return false;
}
@Override
public Tree next () {
Tree t = hall.tree[last];
last++;
return t;
}
}
Step 5.喷洒农药
package model;
//喷洒农药
public class Pren {
public Pren () {
}
public static void main(String[] args) {
Hall hall = new Hall(4);
hall.add(new Tree("Apple"));
hall.add(new Tree("Origance"));
hall.add(new Tree("Pee"));
hall.add(new Tree("Bana"));
for (Iterator i =hall.connectIterator(); i.hasNext(); ) {
String type = ((Tree)(i.next())).getName();
if (type == "Apple")
System.out.println("A");
if (type == "Origance")
System.out.println("O");
if (type == "Pee")
System.out.println("P");
if (type == "Bana")
System.out.println("B");
}
}
}