Retrofit2.3 設(shè)計(jì)模式分析

前言

最近學(xué)校的設(shè)計(jì)模式課程設(shè)計(jì)要求我們選一個(gè)框架進(jìn)行設(shè)計(jì)模式的分析,結(jié)果老師給的題目都是跟Android毫無瓜葛的。這時(shí)候我想起了Retrofit,畢竟有一段時(shí)間曾經(jīng)了解過,據(jù)說是設(shè)計(jì)模式的教科書。所以秉著作死的心態(tài)向老師自定義了題目(真?刺激呀),于是乎在一頓折騰后坎坷的看出大致的模式。這篇文章是一個(gè)學(xué)生黨對框架設(shè)計(jì)模式的分析,可能有錯(cuò)誤的地方,希望能得到大家的指導(dǎo)。

關(guān)于Retrofit

Retrofit是一個(gè)好東西,出自square公司之手,說到square公司自然不得不提一個(gè)大神,那就是jack wharton,很多現(xiàn)在流行的輪子都是他參與造的,比如這次的Retrofit啦,Rxjava啦,黃油刀啦,OkHttp啦等等。這里關(guān)于Retrofit的介紹就詳細(xì)講了,簡書里有很多文章,大家可以搜搜。

Retrofit的基本使用


基本使用方法


使用注解定義一個(gè)接口

筆者用的是Kotlin語言,短短主題五行代碼就可以簡單的完成一次網(wǎng)絡(luò)請求。與OkHttp相比呢也不用自己來寫請求體和回應(yīng)體的解析?;蛟S這就是Retrofit受歡迎的原因之一吧。

? 使用步驟描述:

1.先定義一個(gè)接口,使用@Get,@Path等注解定義,如上圖。

2.創(chuàng)建一個(gè)Retrofit對象,使用其內(nèi)部Builder類來進(jìn)行對Retrofit對象的配置

3.創(chuàng)建一個(gè)Call(請求體),使用Retrofit的create方法傳入定義好的接口

4.調(diào)用已創(chuàng)建Call的方法(接口內(nèi)的方法),傳入用戶想要的參數(shù)

5.執(zhí)行Call,返回一個(gè)回應(yīng)體

6.對回應(yīng)體進(jìn)行一系列用戶需要的操作

框架設(shè)計(jì)模式分析

1.分析框架的初步運(yùn)行流程

Retrofit進(jìn)行配置的流程


創(chuàng)建一個(gè)Call的流程

總結(jié):Retofit類負(fù)責(zé)配置,其中會涉及到一些其他的類,如工廠什么的,但是最后Call的返回邏輯在ServiceMethod類中,ServiceMethod是一個(gè)很關(guān)鍵的類,涉及到了具體運(yùn)行原理和調(diào)用,這里我們只做設(shè)計(jì)模式分析,就不深入啦。

2.深入分析


我們一步一步來,最后面會放上類圖,咱們先不急。

第一步配置

第一步:配置Retrofit

從名字我們就可以看出,毫無疑問配置這一部用了個(gè)構(gòu)造者模式呀(Builder),學(xué)生黨我暗自偷笑。是不是不用看啦??不急不急,我們還是進(jìn)去看一看。

Retrofit類的內(nèi)部屬性和部分方法

可以看到Retrofit類中包含了一個(gè)Builder類,點(diǎn)進(jìn)去一看,是一個(gè)靜態(tài)類(這里就不放圖了),再看看上圖中若干個(gè)addXXX方法和一些其他方法均是返回Builder自身的,還有一個(gè)build()方法返回一個(gè)Retrofit的,這一羅列,哎呀媽呀果真是構(gòu)造者方法,錯(cuò)不了錯(cuò)不了。

知道這里是使用了構(gòu)造方法后,那有什么用呀?因?yàn)榫W(wǎng)絡(luò)請求要配置各種參數(shù),而有些參數(shù)是不必要的,如果不使用構(gòu)造者模式,那Retrofit就必須得寫一大串參數(shù)類型不同的構(gòu)造器,用于對參數(shù)傳入,那代碼就非常的不雅,可讀性也很差,所以就用了個(gè)Builder啦。

等等!就這么完了嗎?但是你仔細(xì)看一下參數(shù),addXXXFactory?里面竟然維護(hù)了一個(gè)叫XXFactory的列表?這難道是...抽象工廠??工廠方法??(學(xué)生黨暗自偷笑,這作業(yè)穩(wěn)了)我們先點(diǎn)進(jìn)去一探究竟


我們點(diǎn)進(jìn)CallAdapter.Factory


驚了,一個(gè)接口里面有個(gè)抽象類,一個(gè)抽象方法
看一下這個(gè)抽象類的實(shí)現(xiàn),有4個(gè),其中有2個(gè)一樣的是因?yàn)榘姹静煌膯栴}


嗯。。沒什么特別,這里就用到了一個(gè)簡單的單例..我們看下一個(gè)


這個(gè)工廠有一個(gè)內(nèi)部類ExecutorCallBackCall,還實(shí)現(xiàn)了Call接口

經(jīng)過一頓分析,可以非常確定這是一個(gè)抽象工廠和工廠方法的設(shè)計(jì)模式。CallAdapter.Factory為抽象工廠,CallAdapter為工廠的產(chǎn)品接口,而上圖中的ExecutorCallAdapterFactory和DefaultCallAdapterFactory為他的實(shí)現(xiàn)類,其中ExecutorCallAdapterFactory中的內(nèi)部類ExecutorCallBackCall為該工廠的產(chǎn)品,實(shí)現(xiàn)了Call接口。

等等!!你說ExecutorCallBackCall是工廠的產(chǎn)品?但無論是從名字上來看還是從接口上來看都不應(yīng)該???因?yàn)樗麑?shí)現(xiàn)了Call接口,但沒有實(shí)現(xiàn)產(chǎn)品應(yīng)該實(shí)現(xiàn)的CallAdapter接口???

的確如此,但是。CallAdapter這名字不覺的很熟悉嗎?沒錯(cuò)Adapter,其實(shí)這里還用了一個(gè)適配模式,而這整一個(gè)工廠最終目的是返回一個(gè)適配器,基于某種兼容目的的適配器。

匿名實(shí)現(xiàn)了CallAdapter接口,其中里面就返回ExecutorCallbackCall

也就是說,產(chǎn)品其實(shí)是他匿名實(shí)現(xiàn)的CallAdapter,只是里面返回了一個(gè)ExecutorCallbackCall,這里利用創(chuàng)建工廠實(shí)現(xiàn)時(shí)傳進(jìn)來的一個(gè)實(shí)現(xiàn)了Java Executor接口的類,來進(jìn)行對參數(shù)call的一個(gè)適配。

這里你會很好奇為什么ExecutorCallbackCall傳進(jìn)一個(gè)實(shí)現(xiàn)了Java Executor接口的類和一個(gè)call做為參數(shù)。


ExecutorCallbackCall實(shí)現(xiàn)的Call接口結(jié)構(gòu)
ExecutorCallbackCall 內(nèi)部的結(jié)構(gòu)

經(jīng)過一番查看,先看看Call接口,ExecutorCallbackCall實(shí)現(xiàn)的Call接口和在適配方法中傳進(jìn)來的call參數(shù)實(shí)現(xiàn)的接口是一毛一樣的??!而從類的結(jié)構(gòu)來看,看屬性delegate的調(diào)用。是的,其實(shí)該類的實(shí)現(xiàn)實(shí)際是交給(委托)給傳進(jìn)來的call參數(shù)(delegate屬性)實(shí)現(xiàn)的,然后只是在使用另一個(gè)傳進(jìn)來的參數(shù)(callbackExecutor)環(huán)境中運(yùn)行【看紅線部分】。

也就是說。這個(gè)類是包裝用的,實(shí)現(xiàn)的功能都是委托給call的。裝飾器模式,不知道為何腦內(nèi)浮現(xiàn)出這幾個(gè)大字...

到此。我們連同裝飾器,適配器整個(gè)抽象工廠,工廠方法分析完畢。這一層套一層,環(huán)環(huán)相扣,這讓人顫栗啊,這?設(shè)計(jì)的太可怕的。多種設(shè)計(jì)模式的運(yùn)用巧而不顯冗雜,豈是我等能做到的!

還有一點(diǎn)要提,我們上課的時(shí)候喜歡把產(chǎn)品接口和抽象方法分開兩個(gè)文件來寫,但是這里是將抽象工廠寫在了接口中。這很巧妙,因?yàn)檫@樣使用的時(shí)候就非常明顯【接口.抽象工廠】,一看就知道這工廠的產(chǎn)品和抽象。而且合在一起寫也不用為命令感到煩惱。

總結(jié)一下:


類圖結(jié)構(gòu)

我們從配置Retrofit為出發(fā)點(diǎn),分析出了抽象工廠,工廠方法,單例,適配器,裝飾器五種模式??赡芫鸵獑柫?,在哪里開始初始化了這個(gè)工廠?有兩個(gè)地方

第一:通過Retofit中Builder的addCallAdapterFactory方法


通過Retofit中Builder的addCallAdapterFactory方法

第二:在我們調(diào)出Builder時(shí),在無參構(gòu)造器中,通過調(diào)用Platform.get()來初始化


Builder的無參構(gòu)造器
Platform類內(nèi)部結(jié)構(gòu)

What??Platform啥玩意?不用擔(dān)心,源代碼作者命名非常好,看名字大概就知道,是平臺嘛,平臺類是干嘛?

可以看出里面有兩個(gè)內(nèi)部靜態(tài)類Java8和Android,還有兩個(gè)defaultCallXXX的方法。到這里我們就可以結(jié)合適配器工廠和這里兩個(gè)內(nèi)部類的類名揣測出適配器是為了適配不同平臺下的運(yùn)行環(huán)境。Android有主線程(UI線程)而Java8則沒有

Android
Java8

這里框架就默認(rèn)實(shí)現(xiàn)了兩個(gè)平臺。Platform類是可繼承的,如果沒有我們的需求就可以繼承該類并實(shí)現(xiàn)自己的平臺。

說要這里第一步配置就說完了,但是返回文中剛開始的地方,你會看到一個(gè)叫converterFactories的列表,這是一個(gè)converter工廠的列表,也是一個(gè)抽象工廠,這里就不詳細(xì)說了,下面只給出類圖,僅供大家參考


畫的好丑。用于解析網(wǎng)絡(luò)返回體結(jié)果。如Gson

第二步:使用create方法傳入接口,返回call


使用步驟的第二步

老規(guī)矩咯,點(diǎn)進(jìn)去看看..

???

哎呀woc這什么東西。學(xué)生黨看不懂,但是我們從Proxy這個(gè)名字可以看出,或許是個(gè)代理模式。經(jīng)過資料查詢后發(fā)現(xiàn),這里是實(shí)現(xiàn)了Java中自帶的動態(tài)代理。何為動態(tài)代理?就是在創(chuàng)建一個(gè)實(shí)例前,你或許要對這個(gè)實(shí)例動點(diǎn)手腳,而我們又不能在創(chuàng)建實(shí)例的是時(shí)候決定要?jiǎng)狱c(diǎn)什么手腳,所以先創(chuàng)建一個(gè)代理對象給你用著先,等你動完該動的手腳,才開始真正創(chuàng)建實(shí)例。也就是說,這里我們調(diào)用create方法本來是要返回一個(gè)call對象的,但是!我們要在傳入需要的參數(shù)后才能真正創(chuàng)建call對象,也就是說在文中開始的第三步后才真正創(chuàng)建了一個(gè)call。

如上圖,create只是創(chuàng)建了個(gè)代理,當(dāng)調(diào)用了代理內(nèi)的方法后(接口放射后的方法)才開始創(chuàng)建真正的實(shí)例

這里筆者就不探究動態(tài)代理如何實(shí)現(xiàn)的了(因?yàn)槲乙膊粫?.)我們繼續(xù)往下看,這動態(tài)代理內(nèi)的代碼

首先是調(diào)用了自身的loadServiceMethod方法,加載(獲得)了一個(gè)ServiceMethod類,然后通過其創(chuàng)建了一個(gè)OkHttpCall實(shí)例,最后調(diào)用了serviceMethod實(shí)例中的一個(gè)callAdapter對象中的adapt方法,最終返回了一個(gè)call。為這個(gè)adapt方法就是之前分析中的工廠方法產(chǎn)品類的方法。

查看一下loadServiceMethod的代碼


非常簡單..

看來Retrofit內(nèi)部保存了一個(gè)ServiceMethod的map(key是從接口中反射出來的方法),沒找到的話就通過ServiceMethod的Builder構(gòu)造一個(gè)(又是一個(gè)構(gòu)造者方法),然后存進(jìn)map中。而ServiceMethod中就會創(chuàng)建callAdapter,這其中又會跳回Retrofit中,從其維護(hù)的callAdapter工廠列表中查找..挺復(fù)雜的,就不說啦,畢竟原則是設(shè)計(jì)模式分析嘛。

再看看用serviceMethod構(gòu)造的OkHttpCall


其實(shí)現(xiàn)了call接口,就是之前在分析適配器講到的call接口一樣的。里面包含了一個(gè)另一個(gè)call接口:rawCall,這個(gè)rawCall與上面的call不同,因?yàn)樗莵碜詏khttp3的。也就是這里的OkHttpCall其實(shí)就是包裝了okhttp3中的call,功能的調(diào)用都委托給他..又一個(gè)裝飾器。

總結(jié)

到這里,Retrofit中用到的設(shè)計(jì)模式我能發(fā)現(xiàn)到的,基本分析完了,里面運(yùn)用了抽象工廠,工廠方法,單例,裝飾器,適配器,動態(tài)代理。光是配置這一步就用了前六種設(shè)計(jì)模式..太可怕了..

希望你們能看懂...虛心接受指導(dǎo)和更正..

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容