設(shè)計(jì)模式解密(10)- 迭代器模式

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

1、簡(jiǎn)介

定義:提供一種方法順序訪問(wèn)一個(gè)聚合對(duì)象中各個(gè)元素, 而又無(wú)須暴露該對(duì)象的內(nèi)部表示;

主要用途:幫助我們遍歷聚合對(duì)象;

關(guān)鍵代碼:定義接口:hasNext, next;

英文:Iterator

類(lèi)型:行為型模式

2、類(lèi)圖及組成

(引)類(lèi)圖:

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

組成:

  抽象容器:一般是一個(gè)接口,提供一個(gè)iterator()方法,例如java中的Collection接口,List接口,Set接口等。

  具體容器:就是抽象容器的具體實(shí)現(xiàn)類(lèi),比如List接口的有序列表實(shí)現(xiàn)ArrayList,List接口的鏈表實(shí)現(xiàn)LinkList,Set接口的哈希列表的實(shí)現(xiàn)HashSet等。

  抽象迭代器:定義遍歷元素所需要的方法,一般來(lái)說(shuō)會(huì)有這么三個(gè)方法:取得第一個(gè)元素的方法first(),取得下一個(gè)元素的方法next(),判斷是否遍歷結(jié)束的方法hasNext(),移出當(dāng)前對(duì)象的方法remove(),

  迭代器實(shí)現(xiàn):實(shí)現(xiàn)迭代器接口中定義的方法,完成集合的迭代。

3、實(shí)例引入

模擬一下迭代器的簡(jiǎn)單實(shí)現(xiàn):

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

package com.designpattern.iterator;/**
 * 抽象迭代器接口
 * @author Json*/public interface Iterator {    
    public boolean hasNext();    
    public Object next();
}

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

  

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

package com.designpattern.iterator;import java.util.ArrayList;/**
 * 具體迭代器實(shí)現(xiàn)
 * @author Json*/public class ConcreteIterator implements Iterator {    private ArrayList list = new ArrayList();    private int cursor = 0;    
    public ConcreteIterator(ArrayList list) {        this.list = list;
    }
    
    @Override    public boolean hasNext() {        if(cursor == list.size()){            return false;
        }        return true;
    }
    
    @Override    public Object next() {        if(this.hasNext()){            return this.list.get(cursor++);
        }        return null;
    }
}

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

  

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

package com.designpattern.iterator;/**
 * 抽象容器
 * @author Json*/public interface Aggregate {    public void add(Object obj);    
    public void remove(Object obj);    
    public Iterator iterator();
}

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

 

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

package com.designpattern.iterator;import java.util.ArrayList;/**
 * 具體容器
 * @author Json*/public class ConcreteAggregate implements Aggregate {    
    private ArrayList list = new ArrayList();
    
    @Override    public void add(Object obj) {
        list.add(obj);
    }

    @Override    public void remove(Object obj) {
        list.remove(obj);
    }

    @Override    public Iterator iterator() {        return new ConcreteIterator(list);
    }

}

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

 測(cè)試:

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

package com.designpattern.iterator;/**
 * 測(cè)試
 * @author Json*/public class Test {    public static void main(String[] args) {
        Aggregate agg = new ConcreteAggregate();
        agg.add("Java");
        agg.add("Ruby");
        agg.add("Python");
        
        Iterator iterator = agg.iterator();        while(iterator.hasNext()){
            String s = (String) iterator.next();
            System.out.println(s);
        }
    }
}

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

 結(jié)果:

Java
Ruby
Python

4、優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

  1、它支持以不同的方式遍歷一個(gè)聚合對(duì)象。 
  2、迭代器簡(jiǎn)化了聚合類(lèi)。 
  3、在同一個(gè)聚合上可以有多個(gè)遍歷。 
  4、在迭代器模式中,增加新的聚合類(lèi)和迭代器類(lèi)都很方便,無(wú)須修改原有代碼。

缺點(diǎn):

  由于迭代器模式將存儲(chǔ)數(shù)據(jù)和遍歷數(shù)據(jù)的職責(zé)分離,增加新的聚合類(lèi)需要對(duì)應(yīng)增加新的迭代器類(lèi),類(lèi)的個(gè)數(shù)成對(duì)增加,這在一定程度上增加了系統(tǒng)的復(fù)雜性。

5、應(yīng)用場(chǎng)景

  1、訪問(wèn)一個(gè)聚合對(duì)象的內(nèi)容而無(wú)須暴露它的內(nèi)部表示。

  2、需要為聚合對(duì)象提供多種遍歷方式。

  3、為遍歷不同的聚合結(jié)構(gòu)提供一個(gè)統(tǒng)一的接口。

6、JDK的迭代器應(yīng)用

JDK中就有大量迭代器的身影:

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

//java中迭代器接口源碼:public interface Iterator<E> {    boolean hasNext();//判斷是否存在下一個(gè)對(duì)象元素
    E next();    void remove(); 
}

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

迭代器模式與集合是緊密聯(lián)系的,可以說(shuō)密不可分,我們只要實(shí)現(xiàn)一個(gè)集合,就需要同時(shí)提供這個(gè)集合的迭代器,就像Java中的Collection,List、Set、Map等,這些集合都有自己的迭代器。假如我們要實(shí)現(xiàn)一個(gè)這樣的新的容器,當(dāng)然也需要引入迭代器模式,給我們的容器實(shí)現(xiàn)一個(gè)迭代器。但是,由于容器與迭代器的關(guān)系太密切了,所以大多數(shù)語(yǔ)言在實(shí)現(xiàn)容器的時(shí)候都給提供了迭代器,并且這些語(yǔ)言提供的容器和迭代器在絕大多數(shù)情況下就可以滿足我們的需要,所以現(xiàn)在需要我們自己去實(shí)踐迭代器模式的場(chǎng)景還是比較少見(jiàn)的;

下面測(cè)試一下JDK迭代器的使用:

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

package com.designpattern.iterator.jdk_use_iterator;import java.util.ArrayList;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;/**
 * 測(cè)試JDK自帶的迭代器
 * @author Json*/public class IteratorTest {    public static void main(String[] args) {
          List list = new ArrayList();  
          for(int i = 0;i < 10;i++){  
              list.add("list_"+i);  
          }  
          Iterator iterList = list.iterator();//List接口實(shí)現(xiàn)了Iterable接口  
          while(iterList.hasNext()){  
              String str = (String)iterList.next();  
              System.out.print(str+"、");  
          }  
    
          System.out.println("");
          
          Map map = new HashMap();  
          for(int i = 0;i < 10;i++){  
              map.put(i,"map_"+i);  
          }  
          Iterator iterMap = map.entrySet().iterator();          while(iterMap.hasNext()){  
              Map.Entry strMap = (Map.Entry)iterMap.next();  
              System.out.print(strMap.getValue()+"、");  
          }  
   }  
}

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

結(jié)果:

list_0、list_1、list_2、list_3、list_4、list_5、list_6、list_7、list_8、list_9、
map_0、map_1、map_2、map_3、map_4、map_5、map_6、map_7、map_8、map_9、

7、迭代器與foreach

從Java5起,Java中新增foreach循環(huán),關(guān)于foreach的語(yǔ)法,可以實(shí)現(xiàn)兩種數(shù)據(jù)類(lèi)型的遍歷,一個(gè)是數(shù)組,一個(gè)便是實(shí)現(xiàn)了Iterable接口的任何類(lèi),今天不討論數(shù)組,我們主要關(guān)注實(shí)現(xiàn)了Iterable接口的類(lèi),是如何使用foreach遍歷的;

foreach循環(huán)允許你在無(wú)需保持傳統(tǒng)for循環(huán)中的索引,或在使用iterator時(shí)無(wú)需調(diào)用while循環(huán)中的hasNext()方法就能遍歷Collection,foreach循環(huán)簡(jiǎn)化了任何Collection或array的遍歷過(guò)程;

但是使用foreach循環(huán)也有兩點(diǎn)需要注意:

1、 foreach循環(huán)通過(guò)iterator實(shí)現(xiàn),使用foreach循環(huán)的對(duì)象必須實(shí)現(xiàn)Iterable接口;

  foreach循環(huán)只適用于實(shí)現(xiàn)了Iterable<T>接口的對(duì)象。由于所有內(nèi)置Collection類(lèi)都實(shí)現(xiàn)了java.util.Collection接口,已經(jīng)繼承了Iterable;所以在使用foreach遍歷Java集合,不用考慮iterator實(shí)現(xiàn);

  但是在以后涉及到自定義聚合對(duì)象時(shí),要注意這一點(diǎn);

2、 在遍歷Collection時(shí),如果要在遍歷期間修改或刪除Collection,則最好通過(guò)Iterator來(lái)實(shí)現(xiàn),否則可能會(huì)發(fā)生“不確定的錯(cuò)誤”。 

附知識(shí)點(diǎn):  在使用Java集合的時(shí)候,都需要使用 Iterator。但是java集合中還有一個(gè)迭代器ListIterator,在使用 List、ArrayList、LinkedList和 Vector的時(shí)候可以使用;

          關(guān)于JAVA中 ListIterator和 Iterator區(qū)別  http://blog.csdn.net/longshengguoji/article/details/41551491

 

關(guān)于第二點(diǎn)測(cè)試?yán)樱?/p>

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

package com.designpattern.iterator.jdk_use_iterator;import java.util.ArrayList;import java.util.Collection;import java.util.Iterator;/**
 * 
 * @author Json*/public class IteratorTest1 {    public static void main(String[] args) {
        Collection<String> list = new ArrayList<String>();
        list.add("張三");
        list.add("李四");
        list.add("王五");
        list.add("趙六");        
        //removeItem1(list);        //removeItem2(list);        removeItem3(list);
    }    
    /**
     * 錯(cuò)誤用法1     */
    public static void removeItem1(Collection<String> list){
        Iterator<String> iterator_1 = list.iterator();        while (iterator_1.hasNext()) {
             String str = iterator_1.next();             if("張三".equals(str)){
                 list.remove(str);
             }
        }
        System.out.println(list);
    }    
    /**
     * 錯(cuò)誤用法2     */
    public static void removeItem2(Collection<String> list){        for (String str : list) {            if("張三".equals(str)){
                list.remove(str);
            }
        }
        System.out.println(list);
    }    
    /**
     * 正確用法     */
    public static void removeItem3(Collection<String> list){
        Iterator<String> iterator_3 = list.iterator();        while (iterator_3.hasNext()) {
             String str = iterator_3.next();             if("張三".equals(str)){
                 iterator_3.remove();
             }
        }
        System.out.println(list);
    }
}

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

8、總結(jié)

迭代器模式就是分離了集合對(duì)象的遍歷行為,抽象出一個(gè)迭代器類(lèi)來(lái)負(fù)責(zé),這樣既可以做到不暴露集合的內(nèi)部結(jié)構(gòu),又可讓外部代碼透明地訪問(wèn)集合內(nèi)部的數(shù)據(jù);

迭代器在平時(shí)需要我們自定義設(shè)計(jì)的情景不是很多,但是可能真會(huì)遇到這樣的需求,所以有必要知道它是怎么實(shí)現(xiàn)的;

 

 

PS:源碼地址   https://github.com/JsonShare/DesignPattern/tree/master 

      

如果您覺(jué)得閱讀本文對(duì)您有幫助,請(qǐng)點(diǎn)一下“推薦”按鈕,您的“推薦”將是我最大的寫(xiě)作動(dòng)力! 
如果標(biāo)題被標(biāo)記為轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明原作者地址,詳見(jiàn)引用 
版權(quán)聲明,轉(zhuǎn)載請(qǐng)注明出處:http://www.cnblogs.com/JsonShare

http://www.cnblogs.com/JsonShare/p/7196615.html