設(shè)計(jì)模式解密(10)- 迭代器模式
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)圖:
組成:
抽象容器:一般是一個(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):
package com.designpattern.iterator;/** * 抽象迭代器接口 * @author Json*/public interface Iterator { public boolean hasNext(); public Object next(); }
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; } }
package com.designpattern.iterator;/** * 抽象容器 * @author Json*/public interface Aggregate { public void add(Object obj); public void remove(Object obj); public Iterator iterator(); }
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); } }
測(cè)試:
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); } } }
結(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中就有大量迭代器的身影:
//java中迭代器接口源碼:public interface Iterator<E> { boolean hasNext();//判斷是否存在下一個(gè)對(duì)象元素 E next(); void remove(); }
迭代器模式與集合是緊密聯(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迭代器的使用:
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()+"、"); } } }
結(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>
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); } }
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