mv-x的含義
M:Model
V:View
X:View和Model的橋梁
MVC
C:Controller
大致定義:
View和Model一般沒有交集,它們的交流通過Controller來進(jìn)行,即:
Model和View由Controller來管理,一般除了View的響應(yīng)由Controller來實(shí)現(xiàn)(由View傳向Controller),Model的變化及View的設(shè)置都會在Controller來實(shí)現(xiàn)(Controller單向傳給其余兩個),View本身不會和Model有任何交集或很少交集(Model的變化直接反映在View上)
如果三者的負(fù)責(zé)不均勻就會有各種變種的MVC,最著名的是Massive View Controller(Controller負(fù)責(zé)絕大部分的事,Model和View的存在感太弱,這種其實(shí)已經(jīng)很接近MVP了)
MVP
P:Presenter
MVP的出現(xiàn)主要是為了完全切斷MVC中View和Model的聯(lián)系,Presenter負(fù)責(zé)Model的變化,同時負(fù)責(zé)View(Controller)的變化,同時接受處理View的事件,從而減少維護(hù)的成本(需要修改時代碼都放在一塊了)
傳統(tǒng)的iOS結(jié)構(gòu)其實(shí)更接近MVP, viewController就相當(dāng)于Presenter,什么都寫在Presenter中
MVVM
VM:ViewModel
實(shí)際關(guān)系:
View(Controller) <-> View Model <-> Model
View 負(fù)責(zé)按照處理好的數(shù)據(jù)顯示界面
View Model 負(fù)責(zé)更新數(shù)據(jù)和展示數(shù)據(jù)到View上,同時數(shù)據(jù)的測試只需要通過View Model就能實(shí)現(xiàn),View Model的重點(diǎn)是為了把View和Model完全隔離開
Model 只負(fù)責(zé)原本Controller中的數(shù)據(jù)處理
在傳統(tǒng)的 MVC 上簡化 View 和 Controller的負(fù)擔(dān)(實(shí)際上iOS架構(gòu)基本是把這兩個合并),順便降低了耦合性,如果愿意的話,實(shí)際上ViewModel是可以復(fù)用的:把View,Model直接的映射抽象化,把常用的方法放進(jìn)去,但這樣還不如做成View的分類
VIPER
一種什么都通過協(xié)議聯(lián)系的結(jié)構(gòu)
優(yōu)點(diǎn)
解藕程度幾乎是所有MVC類型結(jié)構(gòu)中最高的,而且與Core Data幾乎是絕配
缺點(diǎn):過于啰嗦,甚至在小模塊中就需要有十幾二十個類(典型的例子就是https://www.objccn.io/issue-13-5 這個例子,兩個界面加上Core Data就20多個類,還得依照要求配套協(xié)議,如果按照傳統(tǒng)的MVC來實(shí)現(xiàn),不算Core Data,最少3個類就能實(shí)現(xiàn)了)
View視圖
展示界面,接受用戶事件
Entity實(shí)體
相當(dāng)于MVC的Model,并且是純數(shù)據(jù)類,所有數(shù)據(jù)的處理都由Interactor接管
剩下的三個基本是實(shí)現(xiàn)協(xié)議的NSObject,三者不會直接關(guān)聯(lián),而是通過協(xié)議聯(lián)系,甚至Presenter和Controller之間也是通過協(xié)議聯(lián)系:
Presenter展示器
相當(dāng)于MVVM里ViewModel的主要工作,把View的事件傳遞給Interactor,并且處理Interactor的回調(diào)給其他Presenter
實(shí)際上Presenter也不與View交互,而是與Controller交互,但iOS里的View和Controller基本是合并的狀態(tài)所以就直接說是View了
Router路由(有些地方也會稱為WireFrame)
功能基本等價于iOS中的navgationController,Router負(fù)責(zé)管理各個Presenter,創(chuàng)建Controller,匹配Presenter和Controller,跳轉(zhuǎn)Controller
Interactor交互器
負(fù)責(zé)業(yè)務(wù)分析,(聯(lián)網(wǎng))讀取數(shù)據(jù),接受Presenter傳遞過來View的事件,處理并更新Entity,回調(diào)Presenter工作
Interactor還會和data manager/network manager打交道,分離數(shù)據(jù)的讀寫
實(shí)際上Controller還是存在的,只是它的工作變成了準(zhǔn)備View和調(diào)用Presenter,接受Presenter的回調(diào)
VIPER大致拆為兩部分
View層:View-Presenter-Router 和 數(shù)據(jù)層:Interactor-Entity
這兩部分通過Presenter和Interactor通信,盡可能解藕其他部分
實(shí)際上只要能把View,Entity完全分開(通過Interactor分開,只有Interactor能訪問Entity),只要符合這點(diǎn),viper可以以任意組合進(jìn)行
在把View和Entity完全分開后,要怎么用Entity設(shè)置View呢?
這里可以為Entity做一層橋接器,Presenter通過橋接器把Entity轉(zhuǎn)換成能識別的格式(View的專屬ViewModel,這里的Model就真的是Model的意思了)
完整的viper大概長這樣(不是絕對的,但View和Model分開是主要目的):

由上圖可以看出。雖然本質(zhì)還是一個MVC,但解藕程度已經(jīng)非常高了,不同的Entity通過不同的Converter可以用于不同的View,缺點(diǎn)是需要的類真的超多。
Interactor和NetworkManager/DataManager直接通信也存在一個中間模型的轉(zhuǎn)換用作解藕
好處就是測試數(shù)據(jù)正確性的時候,由于View完全獨(dú)立于數(shù)據(jù)層,直接對interactor進(jìn)行測試就能跳過View那部分了,而且開發(fā)流程可以轉(zhuǎn)變?yōu)?,先編寫測試代碼,然后實(shí)現(xiàn)數(shù)據(jù)層的正確性后,再開始開發(fā)View層,還可以先編寫Presenter的測試代碼再實(shí)現(xiàn)界面,最后編寫UITest
實(shí)際上這種多協(xié)議的結(jié)構(gòu),用RAC這類框架能夠更好的簡化調(diào)用
總結(jié):適合復(fù)用程度高的項目,同時要求整個項目都按照一樣的結(jié)構(gòu)構(gòu)件每個模塊的時候,可以取得最大優(yōu)勢,由于過于依賴不同的Model和通過協(xié)議回調(diào),viper更適合使用Swift的項目
ModelController
簡單的解藕還可以通過ModelController把對Model數(shù)據(jù)的操作,計算,甚至是數(shù)據(jù)的更新都放到ModelController中,用的時候就初始化一個ModelController來用,其余時候都只需要用Model就行,雖然叫ModelController,但ModelController是跟View綁定的...操作的事務(wù)都是為了View來操作Model
ModelController為了解藕都不會暴露Model,而是通過提供同質(zhì)的pubic屬性把Model內(nèi)的數(shù)據(jù)合成并傳遞出去(通過ModelController進(jìn)行單向的數(shù)據(jù)流動),如:
class UserModelController {
private var user: User
init(user: User) {
self.user = user
}
var displayName: String {
return "(user.firstName) (user.lastName)"
}
}
該例子來自:https://www.swiftbysundell.com/posts/model-controllers-in-swift ,更具體的ModelController可以查看該文章(純英文)
通過block回調(diào)/代理/KVO等方式在Model變化/更新的時候通知出去更新View
其實(shí)ModelController和ViewModel很像
喵神在MV-X的基礎(chǔ)上總結(jié)了另一套以單向數(shù)據(jù)流為基礎(chǔ)的結(jié)構(gòu),相關(guān)的總結(jié)可以查看:
http://www.itdecent.cn/p/59b3aa74d1df