今天來介紹一個適合構(gòu)建大型APP或比較大的模塊的架構(gòu)-VIPER辣恋;
為什么用VIPER?
略
什么是VIPER淳梦?
伴隨著業(yè)務(wù)的增加甘邀、功能模塊的增漲我們會發(fā)現(xiàn)琅攘,代碼的結(jié)構(gòu)越來越不清晰、測試也越來越難松邪,陷入了一個惡性循環(huán)坞琴;
為了使得代碼便于維護(hù)、結(jié)構(gòu)更清晰逗抑、便于測試剧辐,這時候我們就需要一種好的架構(gòu)方式來組織我們的APP代碼,這時候VIPER就應(yīng)運(yùn)而生邮府;
VIPER這個概念來自于Clean Architecture荧关,VIPER是View, Interactor, Presenter, Entity,Routing,這幾個單詞的縮寫褂傀;在Clean Architecture中將整個APP或者說模塊用專門的不同的層次來分隔忍啤,這使得各個層之間減輕依賴,每個層次負(fù)責(zé)單一的功能仙辟,也符合功能單一的設(shè)計(jì)原則同波,也更加的便于測試;
拆分VIPER
View
- 就是UIViewController/View
- 展示Presenter傳遞過來的數(shù)據(jù)
- 收集用戶輸入叠国、或者事件等交互信息回調(diào)給Presenter
View是被動的未檩,它等待Presenter傳遞內(nèi)容用于展示,它從不主動去向Presenter請求數(shù)據(jù)煎饼;
Presenter
- 負(fù)責(zé)協(xié)調(diào)Interactor和View之間的邏輯
- 將Interactor傳遞過來的Model轉(zhuǎn)轉(zhuǎn)換為ViewModel
- 傳遞ViewModel給View
- 處理從View中傳遞過來的交互事件
- 在需要的時候讹挎,通過調(diào)用Router導(dǎo)航到新頁面
Presenter是整個VIPER架構(gòu)的核心,在Presenter中包含驅(qū)動UI的來邏輯吆玖,他知道什么時候展示什么界面筒溃;它負(fù)責(zé)收集從View中傳遞過來的數(shù)據(jù)或者事件,從而去驅(qū)動Interactor請求數(shù)據(jù)沾乘、或更新UI怜奖;當(dāng)接收到Interactor傳遞過來的數(shù)據(jù),在將數(shù)據(jù)轉(zhuǎn)換成ViewModel后翅阵,將數(shù)據(jù)傳遞給View歪玲;
Interactor
- 包含業(yè)務(wù)邏輯、規(guī)則滿足具體的業(yè)務(wù)需求
- 負(fù)責(zé)將Entity轉(zhuǎn)換為Model
- 知道在數(shù)據(jù)傳遞給Presenter前需要執(zhí)行哪些動作掷匠,比如存儲滥崩、刪除數(shù)據(jù)等
- 不關(guān)心具體的數(shù)據(jù)來源,通過其他的Server API來獲得數(shù)據(jù)
Interactor包含Entity關(guān)聯(lián)到具體業(yè)務(wù)的邏輯讹语,比如只有符合某種條件的Entity才會被傳遞到Presenter钙皮,在其內(nèi)部不應(yīng)該和任何的UI產(chǎn)生依賴關(guān)系;因?yàn)镮nteractor負(fù)責(zé)的是純業(yè)務(wù)邏輯,所以他應(yīng)該很容易進(jìn)行測試或者通過TDD進(jìn)行開發(fā)短条;
Entity
- 業(yè)務(wù)數(shù)據(jù)模型
- 一般直接是沒做過轉(zhuǎn)換處理的接口返回?cái)?shù)據(jù)
- 直接也僅和Interactor產(chǎn)生關(guān)聯(lián)
Router
- 整個模塊的入口及出口
- 一定包含一個方法負(fù)責(zé)創(chuàng)建當(dāng)前模塊导匣,一般是返回一個關(guān)聯(lián)整個模塊的UIViewController;
- 負(fù)責(zé)頁面的導(dǎo)航茸时,從當(dāng)前模塊到其他模塊贡定,比如push、present到新的頁面
在VIPER中可都,頁面的切換響應(yīng)是由Presenter和Router一起承擔(dān)的缓待,由于Presenter負(fù)責(zé)收集用戶的輸入,所以他知道什么時候需要切換到哪個新的頁面渠牲,而Router內(nèi)包含有具體的切換方法命斧,知道怎樣去切換;
我們也可以將Router中創(chuàng)建整個模塊的功能分離出來嘱兼,創(chuàng)建一個單獨(dú)的Buider模塊国葬,這就是VIPER-B;
更加詳細(xì)的劃分關(guān)于VIPER-B芹壕,見下圖(圖片的來源再這里):
其他模塊介紹
Buider
- 整個模塊的入口
- 包含一個創(chuàng)建方法負(fù)責(zé)創(chuàng)建當(dāng)前模塊汇四,一般是返回一個關(guān)聯(lián)整個模塊的UIViewController;
Data Manager
- 是對負(fù)責(zé)網(wǎng)絡(luò)請求的Server踢涌,本地存儲Server的封裝
- 不負(fù)責(zé)具體的網(wǎng)絡(luò)請求或者存儲
- 可以被多個Interactor訂閱
Model
- 是對entity的封裝
- 不是能夠直接展示的數(shù)據(jù)通孽,記得ViewModel的轉(zhuǎn)換時Presenter的工作
ViewModel
- 由Presenter負(fù)責(zé)生成
- 包含有UI需要顯示的內(nèi)容
viper中各個模塊的整合
我們知道了各個層次的職責(zé),將所有的層次組合到一起才是一個完整的架構(gòu)睁壁;怎樣將這些不同的層整合到一起也是一個問題背苦,根據(jù)簡單復(fù)雜有兩個辦法;
方法1:
- 像上圖一樣潘明,view直接持有present行剂,同時view成為present的代理,這樣能夠使得他們之間實(shí)現(xiàn)雙向交互
- router直接被present持有
- interactor直接被presenter持有钳降,interactor回調(diào)或者通知presenter數(shù)據(jù)進(jìn)行更新
方法二:
同樣通過協(xié)議代替上面的持有厚宰,將上面辦法中的持有完全由代理代替,即Presentor遂填、View各自成為各自協(xié)議的代理铲觉;但是需要注意避免循環(huán)引用及完全弱引用,其中一方的代理需要用強(qiáng)引用吓坚,一方代理需要弱引用撵幽;