迭代子模式又叫游标(4)模式,是对象的行为模式。迭代子模式可以顺序地访问一个聚集中的元素而不必暴露聚集的内部表象(internal representation)。
迭代子模式在java中已有实现,只是我们在进行我们自己的软件设计的时候,需要知道这种模式。
迭代子模式有两种实现方式,分别是:白箱聚集与外禀迭代子和黑箱聚集于内禀迭代子
白箱聚集与外禀迭代子:就是说向外界暴露直接修改元素的方法,也就是“宽接口”
黑箱聚集与内禀迭代子:这个就刚好相反而已,也就是“窄接口”
迭代子模式涉及到以下几个角色:
1、抽象迭代子(Iterator)角色:此抽象角色定义出遍历元素所需的接口,如first(游标移动到第一个位置)、nexe(游标移动到下一个位置)。
2、具体迭代子(ConcreteIterator)角色:此角色实现了Iterator接口,并保持迭代过程中的游标位置,每一个游标就是一个Object对象。
3、聚集(Aggregate)角色:此抽象角色给出创建迭代子(Iterator)对象的接口。
4、具体聚集(ConcreteAggregate)角色:实现了创建迭代子(Iterator)对象的接口,返回一个合适的具体迭代子实例。
5、客户端(Demo)角色:持有对聚集及其迭代子对象的引用,调用迭代子对象的迭代接口,也有可能通过迭代子操作聚集元素的增加和删除。
下面我简要说说他们的运行机制,以方便我们更好的理解迭代子模式
先看看白箱聚集与外禀迭代子
首先是我们的客户端是怎么写的:
public class Demo { public void operation(){ Object[] objArray = {"a1","b2","c3","d4","e5","f6","g7"}; //创建聚合对象 AbsIterator agg = new ConcreteAggregate(objArray); //循环输出聚合对象中的值 Iterator it = agg.createIterator(); while(!it.isDone()){ System.out.println(it.currentItem()); it.next(); } } public static void main(String[] args) { Demo demo = new Demo(); demo.operation(); } }
首先我们创建了一个Object的数组 objArray
然后我们就创建了一个聚合对象,这里就相当于我们将数组转换为集合
AbsIterator agg = new ConcreteAggregate(objArray);既然是集合,那他肯定可以迭代,所以我们这里就获得了一个迭代器对象
Iterator it = agg.createIterator();下面就是
isDone判断是否还有数据
it.currentItem获得数据
it.next将游标移动到下一个
整个运行机制就是这样,那么中间的这些方法和类怎么实现呢?
我们先用白箱模式来实现,分为两部分:
第一部分:聚集角色
其顶级接口如下
public abstract class AbsIterator
public abstract class AbsIterator { public abstract Iterator createIterator(); }这个接口获得一个迭代子角色,即我们的迭代器,通过遍历这个迭代子就可以获得我们需要的对象
需要注意的是 这里的返回类型 Iterator是我们自己写的,现在还没写,不用导入java的Iterator类,或者您就直接更名吧
其实现类 public class ConcreteAggregate extends AbsIterator
public class ConcreteAggregate extends AbsIterator{ private Object[] objArray = null; /** * 构造方法,传入聚合对象的内容 * 即将那一个数据转换为集合 */ public ConcreteAggregate(Object[] objArray){ this.objArray = objArray; } /* * 向外加提供一个迭代子对象 * 通过这个方法我们可以得到一个Iterator对象 * 这个对象是通过迭代子对象的有参构造函数获得 */ @Override public Iterator createIterator() { return new ConcreteIterator(this); } /** * 取值方法:向外界提供聚集元素 * 向外界暴露的方法 * 这里的objArray就是我们的当前对象传入的数组 * 通过游标的不同,就获得了这个数组的单个对象 */ public Object getElement(int index){ if(index < objArray.length){ return objArray[index]; }else{ return null; } } /** * 取值方法:向外界提供聚集的大小 * 暴露的方法 */ public int size(){ return objArray.length; } }
第二部分:迭代子角色
首先是抽象迭代子
public interface Iterator
一些基本的接口如下:
public interface Iterator { /** * 迭代方法:移动到第一个元素 */ public void first(); /** * 迭代方法:移动到下一个元素 */ public void next(); /** * 迭代方法:是否为最后一个元素 */ public boolean isDone(); /** * 迭代方法:返还当前元素 */ public Object currentItem(); }注意到了吗,聚集角色的顶级接口的方法返回的Iterator是在这里定义的
迭代子角色的实现类
public class ConcreteIterator implements Iterator
public class ConcreteIterator implements Iterator { //持有被迭代的具体的聚合对象 private ConcreteAggregate agg; //内部索引,记录当前迭代到的索引位置 private int index = 0; //记录当前聚集对象的大小 private int size = 0; public ConcreteIterator(ConcreteAggregate agg){ this.agg = agg; this.size = agg.size(); index = 0; } /** * 迭代方法:返还当前元素 */ @Override public Object currentItem() { return agg.getElement(index); } /** * 迭代方法:移动到第一个元素 */ @Override public void first() { index = 0; } /** * 迭代方法:是否为最后一个元素 */ @Override public boolean isDone() { return (index >= size); } /** * 迭代方法:移动到下一个元素 */ @Override public void next() { if(index < size) { index ++; } } }首先看看代码中的构造方法
public ConcreteIterator(ConcreteAggregate agg){ this.agg = agg; this.size = agg.size(); index = 0; }
聚集实现类的方法
public Iterator createIterator() { return new ConcreteIterator(this); }看见了吗,聚集实现类将当前聚集对象给了ConcreteIterator
ConcreteIterator里用private ConcreteAggregate agg;来保存
那么agg在迭代子中的方法就很好理解了
比如:
public boolean isDone():因为初始情况下index等于0,0肯定是小于 size的撒
public Object currentItem() :既然小于,那就是符合迭代要求,那就打印出元素撒
public Object currentItem() { return agg.getElement(index); }这个方法,我们回到聚集实现类去看看这个方法
public Object getElement(int index){ if(index < objArray.length){ return objArray[index]; }else{ return null; } }这个方法就是获得我们传入数据的index位置的对象
最后就是public void next()方法,这个方法就是将游标index的值加一。
如此循环。
这就是白箱聚集与外禀迭代子的实现方式
我们再来看看他是否是符合开-闭原则的
如果我们一个这个对象还有一个属性,比如移动到上一步:above
那么我们只需要在迭代子接口中增加一个public void above()方法即可,然后实现即可。客户端是没有感知的,唯一能感知就是多了一个方法而已
然后看看黑箱聚集于内禀迭代子
黑箱聚集与白箱聚集唯一不同的就是,黑箱聚集不提供向外暴露的getElement、size等方法,就是说外部可以根据这个方法获得元素,甚至还可以暴露修改index的方法
所以黑箱聚集的实现方式可以用内部类来实现
首先是聚集角色和迭代子角色的接口
他们和白箱聚集是一样的
下面我们看看聚集对象是怎么写的,注意为了便于查看,我将黑箱模式的类名后面都加上了 _h 包括接口
public class ConcreteAggregate_h extends AbsIterator_h{ private Object[] objArray = null; /** * 构造方法,传入聚合对象的具体内容 */ public ConcreteAggregate_h(Object[] objArray){ this.objArray = objArray; } @Override public Iterator_h createIterator() { // TODO 自动生成的方法存根 return new ConcreteIterator_h(); } /* * 不向外接暴露getElement(int index) * size方法也可不暴露 */ public class ConcreteIterator_h implements Iterator_h{ //内部索引,记录当前迭代到的索引位置 private int index = 0; //记录当前聚集对象的大小 private int size = 0; /** * 构造函数 */ public ConcreteIterator_h(){ this.size = objArray.length; index = 0; } /** * 迭代方法:返还当前元素 */ @Override public Object currentItem() { return objArray[index]; } /** * 迭代方法:移动到第一个元素 */ @Override public void first() { index = 0; } /** * 迭代方法:是否为最后一个元素 */ @Override public boolean isDone() { return (index >= size); } /** * 迭代方法:移动到下一个元素 */ @Override public void next() { if(index < size) { index ++; } } } }他的客户端代码和白箱聚集一样
public class Demo { public void operation(){ Object[] objArray = {"a1","b2","c3","d4","e5","f6","g7"}; //创建聚合对象 AbsIterator agg = new ConcreteAggregate(objArray); //循环输出聚合对象中的值 Iterator it = agg.createIterator(); while(!it.isDone()){ System.out.println(it.currentItem()); it.next(); } } public static void main(String[] args) { Demo demo = new Demo(); demo.operation(); } }在白箱聚集中可以这样修改或获得元素
ConcreteAggregate agg1 = new ConcreteAggregate(objArray);
System.out.println(agg1.getElement(2));
而在黑箱模式中就不可以了
黑箱模式也是符合开闭原则的
呵呵,自此完成,我就是按照白话来说的,希望您也能够看懂呀
爆款云服务器s6 2核4G 低至0.46/天,具体规则查看活动详情