迭代子模式又叫游标(Cursor)模式,是对象的行为模式。迭代子模式可以顺序地访问一个聚集中的元素而不必暴露聚集的内部表象(internal representation)。 (学习)
聚集和java聚集
多个对象聚在一起形成的总体称之为聚集(Aggregate),聚集对象是能够包容一组对象的容器对象。聚集依赖于聚集结构的抽象化,具有复杂化和多样性。数组就是最基本的聚集,也是其他的java聚集对象的设计基础。
java聚集对象是实现了共同的java.util.Collection接口的对象,是java语言对聚集概念的直接支持。从1.2版开始,java语言提供了很多种聚集,包括Vector、ArrayList、HashSet、HashMap、Hashtable等,这些都是java聚集的例子。
迭代子模式的结构
迭代子模式有两种实现方式,分别是白箱聚集与外禀迭代子和黑箱聚集于内禀迭代子。
一个典型的由白箱聚集与外禀迭代子组成的系统如下图所示,这个实现中具体迭代子角色是一个外部类,而具体聚集角色向外界提供遍历聚集元素的接口。
迭代子模式涉及到以下几个角色:
- 抽象迭代子(Interator)角色:此抽象角色定义出遍历元素所需的接口
- 具体迭代子(ConcreteIterator)角色:此角色实现了Iterator接口,并保持迭代过程中的游标位置。
- 聚集(Aggregate)角色:此抽象角色给出创建迭代子(Iterator)对象的接口。
- 具体聚集(ConcreteAggregate)角色:实现了创建迭代子(iterator)对象的接口,返回一个合适的具体迭代子实例。
- 客户端角色:持有对聚集及其迭代子对象的引用,调用迭代子对象的迭代接口,也有可能通过迭代子操作聚集元素的增加和删除
源代码
package Iterator /** * 迭代子模式 * 抽象聚集角色类 * */ abstract class Aggregate { /** * 工作方法,创建相应迭代子对象的接品 * */ abstract fun createIterator(): Iterator }
package Iterator /** * 具体聚集角色类,使用了泛型让处理更方便 * */ class ConcreteAggregate<T> constructor(array: Array<T>) : Aggregate() { private var objArray: Array<T>? = null init { objArray = array } override fun createIterator(): Iterator { return ConcreteIterator(this) } /** * 取值方式:向外界提供聚集元素 * */ fun getElement(index: Int): Any? { return if (index < objArray?.size ?: 0) objArray!![index] else null } /** * 取值方法:向外界提供聚集的大小 * */ fun size(): Int { return objArray?.size ?: 0 } }
package Iterator /** * 抽象迭代子角色类 * */ interface Iterator { /** * 移动到第一个元素 * */ fun first() /** * 移动到下一个元素 * */ fun next() /** * 是否为最后一个元素 * */ fun isDone():Boolean /** * 返回当前元素 * */ fun currentItem():Any? }
package Iterator /** * 具体迭代子角色类 * */ class ConcreteIterator<T> constructor(aggregate: ConcreteAggregate<T>) : Iterator { //持有被迭代的具体的聚合对象 private var agg: ConcreteAggregate<T>? = null //内部索引,记录当前迭代到的索引位置 private var index = 0 //记录当前聚集对象的大小 private var size = 0 init { agg = aggregate size = agg?.size() ?: 0 index = 0 } /** * 移动到第一个元素 * */ override fun first() { index = 0 } /** * 移动到下一个元素 * */ override fun next() { if (index < size) { index++ } } /** *是否为最后一个元素 * */ override fun isDone(): Boolean { return index >= size } /** * 返回当前元素 * */ override fun currentItem(): Any? { return agg?.getElement(index) } }
测试
//迭代子模式 val objArray = arrayOf(1,2,3,4,5,6) //创建聚集对象 val agg = ConcreteAggregate(objArray) //循环输出聚集对象中的值 val it = agg.createIterator() while (!it.isDone()){ println(it.currentItem()) it.next() }
打印结果
1 2 3 4 5 6
上面的例子首先创建了一个聚集类实例,然后调用聚集对象的工作方法createInterator()以得到一个迭代子对象。在得到迭代子代象实例后,开始迭代过程,打印出所有的聚集元素。
主动迭代子和被动迭代子
主动迭代子和被动迭代子又称作外部迭代子和内部迭代子。
所谓主动(外部)迭代子,指的是由客户端来控件迭代下一个元素的步骤,客户端会明显调用迭代子的next()待迭代方法,在遍历过程中向前进行。
所谓被动(内部)迭代子,指的是由迭代子自已来控制迭代下一个元素的步骤。因为,如果想要在迭代的过程中完成工作的话,客户端就要把操作传递给迭代子,迭代子在迭代的时候会在每个元素上执行这个操作,类似于java的回调机制。
总体来说外部迭代器比内部迭代器要灵活一些,因此我们常见的实现多属于主动迭代子。
迭代子模式的优点
- 迭代子模式简化了聚集的接口。迭代子具备了一个遍历接口,这样聚集的接口就不必具备遍历接口。
- 每一个聚集对象都可以有一个或多个迭代子对象,每一个迭代子的迭代状态可以是彼此独立的。因此,一个聚集对象可以同时有几个迭代在进行之中。
- 由于遍历算法被封装在迭代子角色里面,因此迭代的算法可以独立于聚集角色变化。