行为模式---之--迭代子模式

迭代子(Iterator)模式又叫游标(Cursor)模式,是对象的行为模式。迭代子模式能够顺序地访问一个聚焦中的元素而没必要暴露聚焦的内部表象。
 
为何汇集须要迭代子?
聚焦对象必须提供适当的方法,容许客户端可以按照一个线性顺序遍历全部的元素对象,把元素对象提取出来或删除掉等 。一个使用聚焦的系统必然会使用这些方法操控聚焦对象,于是在使用聚焦的系统演化过程当中,会出现两类问题:
1.迭代逻辑没有改变,可是须要将一种聚焦换成另外一种聚焦。由于不一样的聚焦具备不一样的遍历接口,因此须要修改客户端代码,以便将已有的迭代调用换成新聚焦对象所要求的接口
2.聚焦不会改变,可是迭代方式须要改变。如原来只须要读取元素和删除元素,但如今须要增长新的元素。这时就只好修改聚焦对象,修改已有的遍历方法,或增长新的方法。
出现这种状况 是由于所涉及的聚焦设计不符合“开-闭”原则,也就是由于没有将不变的结构从系统中抽象出来,与可变成分分割,并将可变部分的各类实现封装起来。一个聪明的作法应当是使用更加抽象的处理方法,使得在进行迭代时,客户端根本无须要知道所使用的聚焦是哪一个类型:当客户端须要使用全新的迭代逻辑时,只须要引进一个新的迭代子对象便可,根本无需修改聚焦对象自己。迭代子模式便 是这样的一个抽象化的概念。这一模式能作到这一点,是由于它将迭代逻辑封装到一个独立的迭代子对象中,从而与聚焦自己分割开。迭代子对象是对遍历的抽象化,不一样的聚焦对象能够提供相同的迭代子对象,从而使客户端无需知道聚焦的底层结构。一个聚焦能够提供多个不一样的迭代子对象,从而使得遍历逻辑的变化不会影响到聚焦对象自己。
    从对变化的封装角度看,迭代子模式将访问聚焦元素的逻辑封装起来,而且使它独立于聚焦对象的封装。这就是提供了汇集存储逻辑与迭代逻辑独立演变的空间,增长了系统的可复用性。可使系统具备在无需修改的状况下进行扩展的能力。从代码重构的角度看,迭代子在客户端和聚焦之间增长了一个中介层,从而使客户端与聚焦之间的通讯从直接变成了间接。这样作的好处是缓冲了客户端的变化对聚焦的影响,以及聚焦的变化对客户端的影响。
 
迭代子模式中的角色:
1.抽象迭代子(Iterator)角色:此抽象角色定义出遍历元素所须要的接口
2.具体迭代子(ConcreteIterator)角色:此角色实现了Iterator接口,并保持迭代过程当中的游标位置
3.聚焦(Aggregate)角色:此抽象角色给出建立迭代了(Iterator)对象的接口
4.具体聚焦(ConcreteAggregate)角色:实现了建立迭代子(Iterator)对象的接口,返回一个合适的具体迭代子实例。
5.客户端角色:持有对聚焦及其迭代子对象的引用,调用迭代子对象的迭代接口,也有可能经过迭代子操做聚焦元素的增长和删除。
 
白箱汇集与外禀迭代子:
一个白箱汇集向外界提供访问本身内部元素的接口(称遍历方法),从而使外禀迭代子能够经过汇集的遍历方法实现迭代功能。
    由于迭代的逻辑是由聚焦对象自己提供的,全部这样的外禀迭代子角色每每仅仅保持迭代的游标位置。在这种实现中具体迭代子角色是一个外部类,而具体汇集角色提供遍历聚焦元素的接口。
 
外禀迭代子的意义:
既然白箱聚焦已经向外界提供了遍历方法,客户端能够自行迭代了,为何还要应用迭代子模式,并建立一个迭代子对象进行迭代呢?迭代子对象和迭代模式会将迭代过程抽象化,将做为迭代消费者的客户端与迭代负责人的迭代子责任分隔开,使得二者能够独立演化。在汇集对象的种类发生变化,或者迭代方法发生变化时,迭代子做为中介层能够吸取变化的因素,而避免修改客户端或聚焦自己。
此外若是系统须要同时针对几个不一样的汇集对象进行迭代,而这些汇集对象所提供的遍历方法有所不一样时,使用迭代子模式和一个外界的迭代子对象是有意义的。具备同一迭代接口的不一样迭代子对象处理具备不一样遍历接口的聚焦对象,使得系统可使用一个统一的迭代接口进行全部的迭代
示例代码:
 1 public class WhiteIterator {
 2     private Iterator it;
 3     private Aggregate agg = new ConcreteAggregate();
 4     public void operation(){
 5         it = agg.createIterator();
 6         while(!it.isDone()){
 7             System.out.println(it.currentIterm());
 8             it.next();
 9         }
10     }
11     public static void main(String[] args) {
12         WhiteIterator wi = new WhiteIterator();
13         wi.operation();
14     }
15 
16 }
17 
18 //抽象汇集角色Aggregate
19 abstract class Aggregate{
20     //工厂方法:返还一个迭代子对象
21     public Iterator createIterator(){
22         return null;
23     }
24 }
25 //抽象迭代子角色
26 interface Iterator{
27     //迭代方法:移动到第一个元素
28     void first();
29     //迭代方法:移动到下一个元素
30     void next();
31     //迭代方法:是不是最后一个元素
32     boolean isDone();
33     //迭代方法:返回当前元素
34     Object currentIterm();
35 }
36 //具体聚焦角色
37 class ConcreteAggregate extends Aggregate{
38     private Object[] obj ={"one","two","three"};
39     //工厂方法:返回一个迭代子对象
40     public Iterator createIterator(){
41         return new ConcreteIterator(this);
42     }
43     //取值方法:向外界提供汇集元素
44     public Object getElement(int index){
45         if(index<obj.length){
46             return obj[index];
47         }else{
48             return null;
49         }
50     }
51     //取值方法向外界提供汇集的大小
52     public int size(){
53         return obj.length;
54     }
55 }
56 
57 //具体迭代子  
58 class ConcreteIterator implements Iterator{
59     private ConcreteAggregate agg;
60     private int index =0;
61     private int size =0;
62     
63     //构造方法,接收一个具体汇集对象为参量,使之能够控制汇集对象
64     public ConcreteIterator(ConcreteAggregate agg){
65         this.agg = agg;
66         size = agg.size();
67         index =0;
68     }
69     //
70 
71     @Override
72     public void first() {
73         index = 0;
74     }
75 
76     @Override
77     public void next() {
78         if(index<size){
79             index++;
80         }
81     }
82 
83     @Override
84     public boolean isDone() {
85         return (index>=size);
86     }
87 
88     @Override
89     public Object currentIterm() {
90         return agg.getElement(index);
91     }
92     
93 }

 

黑箱汇集和内禀迭代子:
一个黑箱汇集不向外部提供遍历本身元素对象的接口,所以,这些元素对象只能够被聚焦内部成员访问。因为内禀迭代子刚好是聚焦内部的成员子类,所以,内禀迭代子对象是能够访问聚焦的元素的。
示例性实现里,具体聚焦类ConcreteAggregate含有一个内部成员类ConcreteIterator,也就是实现了抽象迭代子接口的具体迭代子类,同时汇集并不向外界提供访问本身内部元素的方法。
示例代码:
 1 public class BlackIterator {
 2     private Iterator it;
 3     private Aggregate agg = new ConcreteAggregate();
 4     public void operation(){
 5         it = agg.createIterator();
 6         while(!it.isDone()){
 7             System.out.println(it.currentIterm());
 8             it.next();
 9         }
10     }
11     public static void main(String[] args) {
12         BlackIterator bi = new BlackIterator();
13         bi.operation();
14     }
15 }
16 //抽象聚焦角色
17 abstract class Aggregate{
18     //工厂方法:返回一个迭代子对象
19     public abstract Iterator createIterator();
20 }
21 //抽象迭代子
22 interface Iterator{
23     //迭代方法:移动到第一个元素
24     void first();
25     //迭代方法:移动到下一个元素
26     void next();
27     //迭代方法:是不是最后一个元素
28     boolean isDone();
29     //迭代方法:返回当前元素
30     Object currentIterm();
31 }
32 //具体汇集角色
33 class ConcreteAggregate extends Aggregate{
34     private Object[] obj = {"one","two","three"};
35     
36     @Override
37     public Iterator createIterator() {
38         
39         return new ConcreteIterator();
40     }
41     //内部成员类:具体迭代子类
42     private class ConcreteIterator implements Iterator{
43         private int currentIndex =0;
44 
45         @Override
46         public void first() {
47             currentIndex = 0;
48         }
49 
50         @Override
51         public void next() {
52             if(currentIndex <obj.length){
53                 currentIndex++;
54             }
55         }
56 
57         @Override
58         public boolean isDone() {
59             return currentIndex==obj.length;
60         }
61 
62         @Override
63         public Object currentIterm() {
64             return obj[currentIndex];
65         }
66         
67     }
68 }

 

 
在什么状况下使用内禀迭代与外禀迭代子?
一个外禀迭代子每每仅存储一个游标,所以若是有几个客户端同时进行迭代的话,那么可使用几个外禀迭代子对象,由每个迭代子对象控制一个独立的游标。可是,外禀迭代子对象要求汇集对象向外界提供遍历方法,所以会破坏聚焦的封装。若是某一个客户端能够修改汇集元素的话,迭代会给出不自恰的结果,甚至影响到系统其余部分的稳定性,形成系统崩溃。
    使用外禀迭代子的一个重要理由是它能够被几个不一样的方法和对象共同享用和控制。使用内禀迭代子的优势是不破坏对汇集的封装。
 
迭代子模式的优势:
1.迭代子模式简化了汇集的界面,迭代子具有了一个遍历接口,这样的聚焦的接口就没必要具有遍历接口
2.每个聚焦对象都 能够有一个或一个以上的迭代子对象,每个迭代子的迭代状态是彼此独立的。所以,一个汇集对象能够同时有几个迭代在进行中。
3.因为遍历算法被封装在迭代角色里,所以迭代的算法能够独立于聚焦角色变化。因为客户端拿到的是一个迭代子对象,所以,没必要知道聚焦对象的类型,就能够读取和遍历聚焦对象。这样即便汇集对象的类型发生变化,也不会影响到客户端的遍历过程。
迭代子模式的缺点:
1.迭代子模式给客户端一个汇集被顺序化的错觉,由于大多数状况下汇集的元素并无肯定的顺序,可是迭代必须以必定线性顺序进行。若是客户端误觉得顺序是汇集自己具备的特性而过分依赖于汇集元素的顺序,就会出现错误
2.迭代子模式给出的汇集元素没有类型特征。通常而言,迭代子给出的元素都是Object类型,所以,客户端必须具有这些元素类型的知识才能使用这些元素。
相关文章
相关标签/搜索