ITERATOR 迭代
1、 意图
提供一种方法顺序访问一个聚合对象中各个元素,而又不需要暴露该对象的内部表示。
2、别名
游标
3、关键思想
迭代器模式的关键思想就是将列表的访问和遍历从列表对象中分离出来并放入一个迭代器(iterator)对象中。迭代器类定义了一个访问该列表的接口。迭代器对象负责跟踪当前的元素:即,它知道哪些元素已经遍历过了。
4、 适用性
迭代器模式可用来:
●访问一个聚合对象的内容而无需暴露它的内部表示。
●支持对聚合对象的多种遍历
●为遍历不同的聚合结构提供一个统一的接口(即,支持多态迭代)。
5、 结构
6、 参与者
●Iterator(迭代器);迭代器定义访问和遍历元素的接口。
●ConcreteIterator(具体迭代器);
——具体迭代器实现迭代器接口。
——对该聚合遍历时跟踪当前位置。
●Aggregate(聚合)
——聚合定义创建相应迭代器对象的接口。
●ConcreteAggregate(具体聚合)
——具体聚合实现创建相应迭代器的接口,该操作返回ConcreteIterator的一个适当的实例。
7、 协作
ConcreteIterator跟踪聚合中的当前对象,并能够计算出待遍历的后继对象。
8、 效果
迭代器模式有三个重要的作用:
1)它支持以不同的方式遍历一个聚合;复杂的聚合可用多种方式进行遍历。迭代器模式使得改变遍历算法变得很容易:仅需用一个不同的迭代器的实例代替原先的实例即可。也可以自己定义迭代器的子类以支持新的遍历。
2)迭代器简化了聚合的接口;有了迭代器的遍历接口,聚合本身就不再需要类似的遍历接口了。这样就简化了聚合的接口。
3)在同一个聚合上可以有多个遍历;每个迭代器保持它自己的遍历状态。因此你可以同时进行多个遍历。
9、 实现
迭代器在实现上有许多变化和选择。下面是一些比较重要的实现。实现迭代器模式时常常需要根据所使用的语言提供的控制结构来进行权衡。
1)谁控制该迭代;一个基本的问题是决定由哪一放来控制该迭代器,是迭代器还是使用该迭代器的客户。当由客户来控制迭代时,该迭代器称为一个外部迭代器,而当由迭代器控制迭代时,该迭代器称为一个内部迭代器。使用外部迭代器的客户必须主动推进遍历的步伐,显式地向迭代器请求下一个元素。使用内部迭代器客户只需向其提交一个待执行的操作,而迭代器将聚合中的每一个元素实施该操作。外部迭代器闭内部迭代器更灵活。
2)谁定义遍历算法;迭代器不是唯一可定义遍历算法的地方。聚合本身也可以定义遍历算法,并在遍历工程中用迭代器来存储当前跌倒的状态。我们称这种迭代器为一个游标(cursor),因为它仅用来指示当前位置。客户会以这个游标为一个参数调用该聚合的Next操作,而Next操作将改变这个指示器的状态。如果迭代器负责遍历算法,那么将易于在相同的聚合上使用不同的迭代算法,同时也易于在不同的聚合上重用相同的算法。从另一方面,遍历算法可能需要访问聚合的私有变量。
3)迭代器健壮程度;在遍历一个聚合的时候同时更改这个聚合可能是危险的。如果在遍历聚合的时候添加或删除该聚合元素,可能会导致两次访问同一个元素或者遗漏掉某个元素。一个简单的解决方法是拷贝该聚合,并对该拷贝实施遍历,但一般来说这样做代价太高。一个健壮的迭代器保证插入和删除操作不会收干扰遍历,且不需要拷贝该聚合。有许多方法来实现健壮的迭代器。其中大多数需要向这个聚合注册该迭代器。当插入或删除元素时,该聚合要么调整迭代器的内部状态,要么在内部的维护额外的信息以保证正确的遍历。
4)附加的迭代器操作;迭代器的最小接口由First、Next、IsDone和CurrentItem操作组成。其他一些操作可能也很有用。
5)多态的迭代器。
6)迭代器可有特权访问;迭代器可被看作为创建它的聚合的一个扩展。迭代器和聚合紧密耦合。
7)用于复合对象的迭代器;在Composite模式中的那些递归聚合结构上,外部迭代器可能难以实现,因此在该结构中不同对象处于嵌套聚合的多个不同层次,因此一个外包迭代器为跟踪当前的对象必须存储一条纵贯该Composite的路径。有时使用一个内部迭代器会更容易一些。它仅需递归地调用自己即可,这样就隐式地将路径存储在调用栈中,而无需显式地维护当前对象位置。如果复合中的节点有一个接口可以从一个节点移到它的兄弟节点、父节点和子节点,那么基于游标的迭代器是个更好的选择。游标只需跟踪当前的节点;它可依赖这种节点接口来遍历该复合对象。
8)空迭代器;一个空迭代器(NullIterator)是一个退化的迭代器,它有助于处理边界条件。根据定义,一个NullIterator总是已经完成了遍历:即他的IsDone操作总是返回true。空迭代器使得更容易遍历树形结构的聚合。在遍历过程中的每一个节点,都可向当前的元素请求遍历其各个子结点的迭代器。该聚合元素将返回一个具体的迭代器。但叶节点元素返回NullIterator的一个实例。这就使我们可以用一种统一的方式实现整个结构上的遍历。
10、代码示例
Aggregate
package com.examples.pattern.iterator;
/**
* 聚合对象的接口,定义创建相应迭代器对象的接口
*/
public abstract class Aggregate {
/**
* 工厂方法,创建相应迭代器对象的接口
* @return 相应迭代器对象的接口
*/
public abstract Iterator createIterator();
}
ConcreteAggregate
package com.examples.pattern.iterator;
/**
* 具体的聚合对象,实现创建相应迭代器对象的功能
*/
public class ConcreteAggregate extends Aggregate {
private String[] ss = null;
public ConcreteAggregate(String[] ss){
this.ss = ss;
}
@Override
public Iterator createIterator() {
return new ConcreteIterator(this);
}
public Object get(int index){
Object retObj = null;
if(index < ss.length){
retObj = ss[index];
}
return retObj;
}
public int size(){
return this.ss.length;
}
}
Iterator
package com.examples.pattern.iterator;
/**
* 迭代器接口,定义访问和遍历元素的操作
*/
public interface Iterator {
/**
* 移动到聚合对象的第一个位置
*/
public void first();
/**
* 移动到聚合对象的下一个位置
*/
public void next();
/**
* 判断是否已经移动到聚合对象的最后一个位置
*
* @return true表示已经移到聚合对象的最后一个位置 false表示还没有移动到聚合对象的最后一个位置
*/
public boolean isDone();
/**
* 获取迭代的当前元素
* @return 迭代的当前元素
*/
public Object currentItem();
}
ConcreteIterator
package com.examples.pattern.iterator;
/**
* 具体的迭代器实现对象,示意的是聚合对象为数组的迭代器 不同的聚合对象相应的迭代器实现是不一样的
*/
public class ConcreteIterator implements Iterator {
/**
* 持有被迭代器的具体的聚合对象
*/
private ConcreteAggregate aggregate;
/**
* 内部索引,记录当前迭代到的索引位置 -1表示刚开始的时候,迭代器指向聚合对象第一个对象之前
*/
private int index = -1;
/**
* 构造方法,传入被迭代的具体的聚合对象
*
* @param aggregate
*/
public ConcreteIterator(ConcreteAggregate aggregate) {
this.aggregate = aggregate;
}
@Override
public Object currentItem() {
return this.aggregate.get(index);
}
@Override
public void first() {
index = 0;
}
@Override
public boolean isDone() {
if (index == this.aggregate.size()) {
return true;
}
return false;
}
@Override
public void next() {
if (index < this.aggregate.size()) {
index = index + 1;
}
}
}
Client
package com.examples.pattern.iterator;
public class Client {
public void someOperation() {
String[] names = {"张三","李四","王五"};
//创建聚合对象
Aggregate aggregate = new ConcreteAggregate(names);
//循环输出聚合对象中的值
Iterator it = aggregate.createIterator();
//首先设置迭代器到第一个元素
it.first();
while(!it.isDone()){
//取出当前元素
Object obj = it.currentItem();
System.out.println("this obj == " +obj);
//如果还没有迭代到最后,那么就向下迭代一个
it.next();
}
}
public static void main(String[] args) {
Client client = new Client();
client.someOperation();
}
}