迭代子模式
-
定义:
迭代子模式又叫游标模式,是对象的行为模式。迭代子模式可以顺序的访问一个聚集中的元素而不必暴露聚集的内部表象。迭代子模式具有两种实现方式,分别为白箱聚集于外禀迭代子和黑箱聚集于内禀迭代子。
-
白箱聚集于外禀迭代子:如果一个聚集的接口提供了可以用来修改聚集元素的方法,这个接口就是所谓的宽接口。如果聚集对象为所有对象提供同一个接口,也就是宽接口的话,当然会满足迭代子模式对迭代子对象的要求。但是,这样会破坏对聚集对象的封装。这种提供宽接口的聚集叫做白箱聚集。
-
黑箱聚集于内禀迭代子:如果一个聚集的接口没有提供修改聚集元素的方法,这样的接口就是所谓的窄接口。聚集对象为迭代子对象提供一个宽接口,而为其他对象提供一个窄接口。换而言之,聚集对象的内部接口应当对迭代子对象适当公开,以便迭代子对象能够对聚集对象有足够的了解,从而可以进行迭代操作。但是,聚集对象应当避免向其他对象提供这些方法,因为其他对象应当经过迭代子对象进行这些工作,而不是直接操控聚集对象。在Java语言中,实现双重接口的方法就是将迭代子类设计成聚集类的内部成员类。这样迭代子对象可以像聚集对象的内部成员一样访问聚集对象的内部结构。
-
主动迭代子:是指由客服端控制下一个元素的步骤,客户端会调用next()来获取下一个元素。
-
被动迭代子:是指由迭代子自己来控制嗲一个元素的步骤,如果想要在迭代的过程中完成工作,就需要把操作传给迭代子,迭代子会在每个元素上执行,类似于回调机制。
-
静态迭代子:由聚集对象创建,并持有聚集对象的一份快照,在产生后这个快照的内容就不再变化。客户端可以继续修改原聚集的内容,但是迭代子对象不会反映出聚集的新变化。静态迭代子的好处是它的安全性和简易性,换而言之,静态迭代子易于实现,不容易出现错误。但是由于静态迭代子将原聚集复制了一份,因此它的短处是对时间和内存资源的消耗。
-
动态迭代子:与静态迭代子完全相反,在迭代子被产生之后,迭代子保持着对聚集元素的引用,因此,任何对于聚集元素内容的修改都会在迭代子对象上反映出来。完整的动态迭代子不容易实现,但是简化的动态迭代子并不难实现,大多数的Java设计师遇到的迭代子都是这种简化的动态迭代子。
-
Fail Fast:如果聚集对象的元素在一个动态迭代子的迭代过程中发生变化时,迭代过程会受到影响而变得不能进行。这时候,迭代子就应当立即抛出一个异常。这种迭代子就是实现了Fail Fast功能的迭代子。
-
-
UML:
- Iterator:抽象角色定义遍历的对象所需的接口。
- ConcreteIterator:实现Iterator接口,保持迭代过程中游标的位置。
- Aggregate:抽象接口,创建迭代子Iterator对象的接口。
- ConcreteAggregate:实现Aggregate接口,具体实现一个迭代子对象实例。
-
优点:
-
迭代子模式简化了聚集的接口。迭代子具备了一个遍历接口,这样聚集的接口就不必具备遍历接口。
-
每一个聚集对象都可以有一个或多个迭代子对象,每一个迭代子对象的迭代状态可以是彼此独立的。因此,一个聚集对象可以同时有几个迭代在进行之中。
-
由于遍历方法被封装在迭代子角色里面,因此迭代的算法可以独立于聚集角色变化。
-
-
样例:
-
白箱聚集于外禀迭代子模式:
public abstract class Aggregate {
/**
* 工厂方法,创建相应迭代子对象的接口
* @return
*/
public abstract Iterator createIterator();
}```java public class ConcreteAggregate extends Aggregate { private Object[] objArray = null; /** * 构造方法,传入聚合对象的具体内容 * @param objArray */ public ConcreteAggregate(Object[] objArray) { this.objArray = objArray; } @Override public Iterator createIterator() { return new ConcreteIterator(this); } /** * 取值方法,向外界提供聚集元素 * @param index * @return */ public Object getElement(int index) { if (index < objArray.length) { return objArray[index]; } else { return null; } } /** * 取值方法,向外界提供聚集的大小 * @return */ public int size() { return objArray.length; } }
public interface Iterator { /** * 迭代方法,移动至第一个元素 */ public void first(); /** * 迭代方法,移动至下一个元素 */ public void next(); /** * 迭代方法,是否为最后一个元素 */ public boolean isDone(); /** * 迭代方法,返回当前元素 */ public Object currentItem(); }
public class ConcreteIterator implements Iterator { /** * 持有被迭代的具体的聚合对象 */ private ConcreteAggregate agg; /** * 内部索引,记录当前迭代到的索引位置 */ private int index = 0; /** * 记录当前索引对象的大小 */ private int size = 0; /** * 构造函数,传入具体的聚合对象,并获取聚合对象大小 * @param agg */ public ConcreteIterator(ConcreteAggregate agg) { this.agg = agg; this.size = agg.size(); this.index = 0; } /** * 移动至第一个元素 */ public void first() { this.index = 0; } /** * 迭代方法,移动到下一个元素 */ public void next() { if (this.index < this.size) { this.index++; } } /** * 迭代方法,是否是最后一个元素 */ public boolean isDone() { return (this.index >= this.size); } /** * 迭代方法,返还当前位置元素 */ public Object currentItem() { return this.agg.getElement(this.index); } }
-
黑盒聚集于内禀迭代子模式:
public abstract class Aggregate { /** * 工厂方法,创建相应迭代子对象的接口 * @return */ public abstract Iterator createIterator(); }
public interface Iterator { /** * 迭代方法,移动至第一个元素 */ public void first(); /** * 迭代方法,移动至下一个元素 */ public void next(); /** * 迭代方法,是否为最后一个元素 */ public boolean isDone(); /** * 迭代方法,返回当前元素 */ public Object currentItem(); }
public class ConcreteAggregate extends Aggregate { private Object[] objArray = null; /** * 构造方法,传入聚合对象的具体内容 * * @param objArray */ public ConcreteAggregate(Object[] objArray) { this.objArray = objArray; } @Override public Iterator createIterator() { return new ConcreteIterator(); } /** * 内部成员类,具体迭代子类 * @author chenshuaishuai * */ private class ConcreteIterator implements Iterator { /** * 内部索引,记录当前迭代到的索引位置 */ private int index = 0; /** * 记录当前聚集对象的大小 */ private int size = 0; /** * 构造函数,设置聚集对象大小和起始索引 */ public ConcreteIterator() { this.size = objArray.length; this.index = 0; } /** * 移动至第一个元素 */ @Override public void first() { this.index = 0; } /** * 迭代方法,移动到下一个元素 */ @Override public void next() { if (this.index < this.size) { this.index++; } } /** * 迭代方法,是否是最后一个元素 */ @Override public boolean isDone() { return (this.index >= this.size); } /** * 迭代方法,返还当前位置元素 */ @Override public Object currentItem() { return objArray[this.index]; } } }
-