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

迭代子(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類型,所以,客戶端必須具有這些元素類型的知識才能使用這些元素。
相關文章
相關標籤/搜索