Java設(shè)計(jì)模式之迭代器模式
本文介紹設(shè)計(jì)模式中的迭代器模式,首先通俗的解釋迭代器模式的基本概念和對(duì)應(yīng)的四個(gè)角色,并根據(jù)四個(gè)角色舉一個(gè)典型的實(shí)例,為了加強(qiáng)知識(shí)的連貫性,我們以Jdk源碼集合中使用迭代器模式的應(yīng)用進(jìn)一步說(shuō)明,最后說(shuō)明迭代器模式的應(yīng)用場(chǎng)景和優(yōu)缺點(diǎn)。
讀者可以拉取完整代碼本地學(xué)習(xí),實(shí)現(xiàn)代碼均測(cè)試通過(guò)上傳到碼云,本地源碼下載。
一、概念理解
迭代器模式官方解釋就是提供一個(gè)對(duì)象來(lái)順序訪問(wèn)聚合對(duì)象中的一系列數(shù)據(jù),而不暴露聚合對(duì)象的內(nèi)部表示。何為聚合對(duì)象呢?最典型的就是集合類。
大白話也就是,集合中的數(shù)據(jù)是私有的,集合中不應(yīng)該提供直接遍歷的方法,要定義一個(gè)新的對(duì)象用于訪問(wèn)這個(gè)集合。
既然是一個(gè)專門(mén)用來(lái)遍歷的對(duì)象,一個(gè)被遍歷的聚合對(duì)象,很顯然至少有兩個(gè)對(duì)象,迭代器對(duì)象、聚合對(duì)象,由于遵循面向接口編程的原則,迭代器對(duì)象和聚合對(duì)象應(yīng)該抽象出來(lái)接口,那自然而然就是應(yīng)該有四個(gè)角色:
抽象聚合(InterfaceAggregate)角色:定義存儲(chǔ)、添加、刪除聚合元素以及創(chuàng)建迭代器對(duì)象的接口。
具體聚合(ConcreteAggregate)角色:實(shí)現(xiàn)抽象聚合類,返回一個(gè)具體迭代器的實(shí)例。
抽象迭代器(Iterator)角色:定義訪問(wèn)和遍歷聚合元素的接口,通常包含 hasNext()、next() 等方法。
具體迭代器(Concretelterator)角色:實(shí)現(xiàn)抽象迭代器接口中所定義的方法,完成對(duì)聚合對(duì)象的遍歷,記錄遍歷的當(dāng)前位置。
基于四個(gè)角色我們舉一個(gè)典型案例。
二、案例實(shí)現(xiàn)
應(yīng)該是有四個(gè)類
抽象聚合角色,用于定義增刪改查元素的統(tǒng)一規(guī)范接口,和創(chuàng)建迭代器對(duì)象的方法
具體聚合角色,實(shí)現(xiàn)抽象聚合角色方法
抽象迭代器角色,定義遍歷元素的統(tǒng)一規(guī)范接口
具體迭代器,實(shí)現(xiàn)抽象迭代器角色的方法。
抽象聚合角色:
/** * 抽象聚合角色 * @author tcy * @Date 13-09-2022 */ public interface InterfaceAggregate { /** * 增加對(duì)象 * @param obj 對(duì)象 */ void add(Object obj); /** * 移除對(duì)象 * @param obj 對(duì)象 */ void remove(Object obj); /** * 調(diào)用迭代器 * @return 迭代器 */ Iterator getIterator(); }
具體聚合角色:
/** * 具體聚合角色 * @author tcy * @Date 13-09-2022 */ public class ConcreteAggregate implements InterfaceAggregate{ private List<Object> list = new ArrayList<>(); @Override public void add(Object obj) { list.add(obj); } @Override public void remove(Object obj) { list.remove(obj); } @Override public Iterator getIterator() { return new Concretelterator(list); } }
抽象迭代器角色:
/** * 抽象迭代器 * @author tcy * @Date 13-09-2022 */ public interface Iterator<E> { /** * 刪除對(duì)象 * @return 對(duì)象 */ Object remove(); /** * 調(diào)用下一個(gè)對(duì)象 * @return 對(duì)象 */ E next(); /** * 迭代器中是否還有下一個(gè)對(duì)象 * @return */ boolean hasNext(); /** * 遍歷迭代器中剩余的對(duì)象 * @param action */ default void forEachRemaining(Consumer<? super E> action) { Objects.requireNonNull(action); while (hasNext()) action.accept(next()); } }
具體迭代器角色:
/** * 具體迭代器角色 * @author tcy * @Date 13-09-2022 */ public class Concretelterator implements Iterator{ private List<Object> list = null; private int index = -1; public Concretelterator(List<Object> list) { this.list = list; } @Override public Object remove() { index = list.size(); Object obj = list.get(index); list.remove(obj); return obj; } @Override public Object next() { Object obj = null; if (this.hasNext()) { obj = list.get(++index); } return obj; } @Override public boolean hasNext() { if (index < list.size() - 1) { return true; } else { return false; } } }
客戶端調(diào)用:
/** * @author tcy * @Date 13-09-2022 */ public class Client { public static void main(String[] args) { ConcreteAggregate concreteAggregate=new ConcreteAggregate(); concreteAggregate.add("老王"); concreteAggregate.add("小王"); concreteAggregate.add("小張"); System.out.println("Aggregate聚合對(duì)象有:"); Iterator iterator=concreteAggregate.getIterator(); while (iterator.hasNext()){ Object next = iterator.next(); System.out.println(next.toString()); } //遍歷剩下的角色 iterator.forEachRemaining(ele -> System.out.println(ele)); } }
迭代器實(shí)現(xiàn)邏輯比較清晰,理解起來(lái)難度也不大,了解了該設(shè)計(jì)模式,趁熱打鐵看迭代器模式在源碼中的應(yīng)用。
三、源碼應(yīng)用
迭代器模式在Jdk中的集合類中有著廣泛的應(yīng)用,我們以ArrayList作為典型。
在ArrayList實(shí)現(xiàn)迭代器時(shí),同樣是有四個(gè)角色。
List抽象聚合類;
ArrayList具體聚合角色;
Iterator抽象迭代器;
ArrayList內(nèi)部類Itr是具體迭代器;
我們可以看到ArrayList是把具體聚合角色和具體迭代器都寫(xiě)在一個(gè)類中,Itr作為具體迭代對(duì)象是以內(nèi)部類的形式。
ArrayList其實(shí)和我們案例中的方法長(zhǎng)的很像,只不過(guò)ArrayList中定義了更多的方法,而且ArrayList還有一個(gè)內(nèi)部類ListItr。
其實(shí)是迭代器的增強(qiáng)版,在繼承Itr的基礎(chǔ)之上實(shí)現(xiàn)ListIterator接口。
Iterator迭代器除了,hasNext()、next()、remove()方法以外,還有一個(gè)特別的forEachRemaining()方法,我們重點(diǎn)說(shuō)下forEachRemaining()方法,該方法代表的意思是遍歷剩下的集合。
比如我們已經(jīng)調(diào)用了該集合中的第一個(gè)元素,那么遍歷時(shí)候就會(huì)自動(dòng)忽略第一個(gè)元素,遍歷剩下的元素。
我們寫(xiě)一個(gè)測(cè)試方法看效果:
public class Client { public static void main(String[] args) { // jdk ArrayList迭代器 //創(chuàng)建一個(gè)元素類型為Integer的集合 Collection<String> collection = new ArrayList<>(); //向集合中添加元素 collection.add("老王"); collection.add("小王"); collection.add("小張"); //獲取該集合的迭代器 java.util.Iterator<String> iteratorJdk= collection.iterator(); System.out.println("Arraylist聚合對(duì)象有:"); //調(diào)用迭代器的經(jīng)過(guò)集合實(shí)現(xiàn)的抽象方法遍歷集合元素 while(iteratorJdk.hasNext()) { System.out.println(iteratorJdk.next()); } //調(diào)用forEachRemaining()方法遍歷集合元素 iteratorJdk.forEachRemaining(ele -> System.out.println(ele)); } }
Arraylist聚合對(duì)象有:
老王
小王
小張
正常情況下,會(huì)打印兩次集合對(duì)象中的信息,實(shí)際上只打印了一次,正是由于next調(diào)用過(guò)的元素,forEachRemaining不會(huì)再調(diào)。
看到這,想必你對(duì)迭代器已經(jīng)有了初步的了解,當(dāng)在遍歷元素時(shí),除了使用for循環(huán)遍歷元素以外,提供了另外一種方式遍歷元素。
案例很好理解,源碼中的應(yīng)用也看得懂,但是實(shí)際開(kāi)發(fā)中迭代器對(duì)象什么時(shí)候用呢?想必大部分人并不是很清晰。
接著看迭代器對(duì)象的應(yīng)用場(chǎng)景和優(yōu)缺點(diǎn),看從中能不能找到答案。
四、總結(jié)
當(dāng)一個(gè)對(duì)象是一個(gè)聚合對(duì)象且需要對(duì)外提供遍歷方法時(shí),可以使用迭代器模式,也即實(shí)際業(yè)務(wù)中定義的有聚合對(duì)象,里面存放了我們需要的業(yè)務(wù)數(shù)據(jù),為了讓業(yè)務(wù)數(shù)據(jù)的職責(zé)更清晰,我們就可以將編輯的方法提取出來(lái),另外定義一個(gè)迭代器對(duì)象用于遍歷數(shù)據(jù)。
迭代器方式提供了不同的方式遍歷聚合對(duì)象,增加新的聚合類和迭代器類都是比較方便的,Java集合類中龐大的家族采用迭代器模式就是基于這種優(yōu)點(diǎn)。
迭代器模式有設(shè)計(jì)模式的通用缺點(diǎn)——系統(tǒng)復(fù)雜性,迭代器模式將數(shù)據(jù)存儲(chǔ)和數(shù)據(jù)遍歷分開(kāi),增加了類的個(gè)數(shù)。
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(guān)鏈接
相關(guān)文章
RabbitMQ開(kāi)啟SSL與SpringBoot連接測(cè)試的配置方法
本文基于 CentOS 7 + Git + OpenSSL + yum 安裝的 RabbitMQ,需要讀者提交安裝好。其他方式也可變通參考本文。對(duì)RabbitMQ開(kāi)啟SSL與SpringBoot連接測(cè)試相關(guān)知識(shí)感興趣的朋友一起看看吧2022-01-01Spring?IoC容器Bean作用域的singleton與prototype使用配置
這篇文章主要為大家介紹了Spring?IoC容器Bean作用域的singleton與prototype使用配置詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12feign調(diào)用第三方接口,編碼定義GBK,響應(yīng)中文亂碼處理方式
這篇文章主要介紹了feign調(diào)用第三方接口,編碼定義GBK,響應(yīng)中文亂碼處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01深層剖析java應(yīng)用開(kāi)發(fā)中MyBayis緩存
這篇文章主要為大家深層剖析java開(kāi)發(fā)中MyBayis緩存,文中講解了Mybatis緩存的分類以及使用的方式,有需要的朋友可以借鑒參考下,希望可以有所幫助2021-09-09新手小白入門(mén)必學(xué)JAVA面向?qū)ο笾鄳B(tài)
說(shuō)到多態(tài),一定離不開(kāi)其它兩大特性:封裝和繼承,下面這篇文章主要給大家介紹了關(guān)于新手小白入門(mén)必學(xué)JAVA面向?qū)ο笾鄳B(tài)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-02-02SSH框架網(wǎng)上商城項(xiàng)目第18戰(zhàn)之過(guò)濾器實(shí)現(xiàn)購(gòu)物登錄功能的判斷
這篇文章主要為大家詳細(xì)介紹了SSH框架網(wǎng)上商城項(xiàng)目第18戰(zhàn):過(guò)濾器實(shí)現(xiàn)購(gòu)物登錄功能的判斷,感興趣的小伙伴們可以參考一下2016-06-06Spring?Cloud?通過(guò)?Gateway?webflux實(shí)現(xiàn)網(wǎng)關(guān)異常處理
在某一個(gè)服務(wù)中出現(xiàn)異常,通過(guò)@ControllerAdvice?+?@ExceptionHandler?統(tǒng)一異常處理,即使在微服務(wù)架構(gòu)中,也可以將上述統(tǒng)一異常處理放入到公共的微服務(wù)中,這樣哪一個(gè)微服務(wù)需要,直接引入模塊,本文重點(diǎn)介紹Spring?Cloud?通過(guò)?Gateway?webflux實(shí)現(xiàn)網(wǎng)關(guān)異常處理,一起看看吧2023-11-11