设计模式之迭代子模式
迭代子模式又叫游標(biāo)(Cursor)模式,是對象的行為模式。
迭代子模式的定義
迭代子模式可以順序地訪問一個(gè)聚集中的元素而不必暴露聚集的內(nèi)部表象。我們常見的集合有很多種類,其頂層數(shù)據(jù)存儲(chǔ)和組織方式的不同導(dǎo)致了我們在對數(shù)據(jù)進(jìn)行遍歷的時(shí)候存在一些差異,迭代器模式就是通過實(shí)現(xiàn)某種統(tǒng)一的方式來實(shí)現(xiàn)對不同的集合的遍歷,同時(shí)又不暴露出其底層的數(shù)據(jù)存儲(chǔ)和組織方式。
例如,如果沒有使用Iterator,遍歷一個(gè)數(shù)組的方法是使用索引:
for(int i=0; i<array.size(); i++) { get(i) } 復(fù)制代碼而訪問一個(gè)鏈表(LinkedList)又必須使用while循環(huán):
while((e=e.next())!=null) { e.data() } 復(fù)制代碼以上兩種方法客戶端都必須事先知道集合的內(nèi)部結(jié)構(gòu),訪問代碼和集合本身是緊耦合,無法將訪問邏輯從集合類和客戶端代碼中分離出來,每一種集合對應(yīng)一種遍歷方法,客戶端代碼無法復(fù)用。
更恐怖的是,如果以后需要把ArrayList更換為LinkedList,則原來的客戶端代碼必須全部重寫。
為解決以上問題,Iterator模式總是用同一種邏輯來遍歷集合:
for(Iterator it = yourCollection.iterater(); it.hasNext(); ) { ... } 復(fù)制代碼客戶端自身不維護(hù)遍歷集合的"指針",所有的內(nèi)部狀態(tài)(如當(dāng)前元素位置,是否有下一個(gè)元素)都由Iterator來維護(hù),而這個(gè)Iterator由集合類通過工廠方法生成,因此,它知道如何遍歷整個(gè)集合??蛻舳藦牟恢苯雍图项惔蚪坏?#xff0c;它總是控制Iterator,向它發(fā)送"向前","向后","取當(dāng)前元素"的命令,就可以間接遍歷整個(gè)集合。
迭代子模式的結(jié)構(gòu)
迭代模式中有如下的角色:
迭代子模式的結(jié)構(gòu)- 迭代器角色(Iterator): 負(fù)責(zé)定義訪問和遍歷元素的接口。
- 具體迭代器角色(Concrete Iterator):實(shí)現(xiàn)迭代器接口,并要記錄遍歷中的當(dāng)前位置。
- 容器角色(Container): 負(fù)責(zé)提供創(chuàng)建具體迭代器角色的接口。
- 具體容器角色(Concrete Container):實(shí)現(xiàn)創(chuàng)建具體迭代器角色的接口, 這個(gè)具體迭代器角色與該容器的結(jié)構(gòu)相關(guān)。
迭代子模式的實(shí)現(xiàn)
迭代器接口實(shí)現(xiàn),定義了獲取第一個(gè)節(jié)點(diǎn)的方法,前一個(gè)節(jié)點(diǎn)和后一個(gè)節(jié)點(diǎn),以及判斷是否有下一個(gè)節(jié)點(diǎn)。
public interface Iterator {public Object first();public Object previous();public Object next();public boolean hasNext(); } 復(fù)制代碼具體實(shí)現(xiàn)迭代器,實(shí)現(xiàn)上述接口定義的方法。
public class MyIterator implements Iterator{private List<Object> list;private int index = 0;public MyIterator(List<Object> list) {this.list = list;}public Object previous() {if((this.index - 1) < 0){return null;}else{return this.list.get(--index);}}public Object next() {if((this.index + 1) >= this.list.size()){return null;}else{return this.list.get(++index);}}public boolean hasNext() {if(this.index < (this.list.size() - 1)){return true;}return false;}public Object first() {if(this.list.size() <= 0){return null;}else{return this.list.get(0);}} } 復(fù)制代碼容器定義,定義了兩個(gè)抽象方法,用來設(shè)置具體的迭代器實(shí)現(xiàn)以及注入容器中的元素。
public abstract class Container {public abstract Iterator iterator();public abstract void put(Object obj); } 復(fù)制代碼具體的容器類基于List,實(shí)現(xiàn)抽象方法。
public class MyContainer extends Container{private List<Object> list;public MyContainer() {this.list = new ArrayList<Object>();}public void put(Object obj){this.list.add(obj);}public Iterator iterator() {return new MyIterator(list);} } 復(fù)制代碼客戶端測試類。設(shè)置元素,并使用迭代器進(jìn)行遍歷。
public class ClientTest {public static void main(String[] args) {//創(chuàng)建一個(gè)自定義容器,直接使用ArrayList的實(shí)現(xiàn)Container strContainer = new MyContainer();strContainer.put("001");strContainer.put("002");Iterator myIterator = strContainer.iterator();//使用迭代器遍歷System.out.println(myIterator.first());while (myIterator.hasNext()) {System.out.println(myIterator.next());}} } 復(fù)制代碼類圖總結(jié)
Iterator模式是用于遍歷集合類的標(biāo)準(zhǔn)訪問方法。它可以把訪問邏輯從不同類型的集合類中抽象出來,從而避免向客戶端暴露集合的內(nèi)部結(jié)構(gòu)。
適用場景:
- 訪問一個(gè)聚合對象的內(nèi)容而無須暴露它的內(nèi)部表示。
- 需要為聚合對象提供多種遍歷方式。
- 為遍歷不同的聚合結(jié)構(gòu)提供一個(gè)統(tǒng)一的接口。
優(yōu)點(diǎn):
- 它支持以不同的方式遍歷一個(gè)聚合對象。
- 迭代器簡化了聚合類。在同一個(gè)聚合上可以有多個(gè)遍歷。
- 在迭代器模式中,增加新的聚合類和迭代器類都很方便,無須修改原有代碼。
- 系統(tǒng)需要訪問一個(gè)聚合對象的內(nèi)容而無需暴露它的內(nèi)部表示。
缺點(diǎn):
- 由于迭代器模式將存儲(chǔ)數(shù)據(jù)和遍歷數(shù)據(jù)的職責(zé)分離,增加新的聚合類需要對應(yīng)增加新的迭代器類,類的個(gè)數(shù)成對增加,這在一定程度上增加了系統(tǒng)的復(fù)雜性。
- 迭代器模式在遍歷的同時(shí)更改迭代器所在的集合結(jié)構(gòu)會(huì)導(dǎo)致出現(xiàn)異常。所以使用foreach語句只能在對集合進(jìn)行遍歷,不能在遍歷的同時(shí)更改集合中的元素。
訂閱最新文章,歡迎關(guān)注我的公眾號
參考
總結(jié)
以上是生活随笔為你收集整理的设计模式之迭代子模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 生成器表达式 内置函数
- 下一篇: ASP.NET Core Web API