2017-08-19rickytang0Cocoa開(kāi)發(fā)者社區(qū)
MVC
全稱是 Model View Controller只磷,是模型 (model)-視圖 (view)-控制器 (controller) 的縮寫(xiě)。它表示的是一種常見(jiàn)的客戶端軟件開(kāi)發(fā)框架锨阿。
現(xiàn)在,MVC 已經(jīng)成為主流的客戶端編程框架何荚,在 iOS 開(kāi)發(fā)中毯盈,系統(tǒng)為我們實(shí)現(xiàn)好了公共的視圖類(lèi):UIView,和控制器類(lèi):UIViewController湿刽。大多數(shù)時(shí)候的烁,我們都需要繼承這些類(lèi)來(lái)實(shí)現(xiàn)我們的程序邏輯,因此诈闺,我們幾乎逃避不開(kāi) MVC 這種設(shè)計(jì)模式渴庆。
但是,幾十年過(guò)去了雅镊,我們對(duì)于 MVC 這種設(shè)計(jì)模式真的用得好嗎襟雷?其實(shí)不是的,MVC 這種分層方式雖然清楚仁烹,但是如果使用不當(dāng)耸弄,很可能讓大量代碼都集中在 Controller 之中,讓 MVC 模式變成了 Massive View Controller 模式卓缰。
Controller 的臃腫問(wèn)題何解计呈?
我們來(lái)看看 MVC 這種架構(gòu)的特點(diǎn)砰诵。其實(shí)設(shè)計(jì)模式很多時(shí)候是為了Don't repeat yourself原則來(lái)做的,該原則要求能夠復(fù)用的代碼要盡量復(fù)用捌显,來(lái)保證重用茁彭。在 MVC 這種設(shè)計(jì)模式中,我們發(fā)現(xiàn) View 和 Model 都是符合這種原則的扶歪。
對(duì)于 View 來(lái)說(shuō)理肺,你如果抽象得好,那么一個(gè) App 的動(dòng)畫(huà)效果可以很方便地移植到別的 App 上善镰,而 Github 上也有很多 UI 控件妹萨,這些控件都是在 View 層做了很好的封裝設(shè)計(jì),使得它能夠方便地開(kāi)源給大家復(fù)用炫欺。
對(duì)于 Model 來(lái)說(shuō)乎完,它其實(shí)是用來(lái)存儲(chǔ)業(yè)務(wù)的數(shù)據(jù)的,如果做得好竣稽,它也可以方便地復(fù)用囱怕。比如我當(dāng)時(shí)在做有道云筆記 iPad 版的時(shí)候,我們就直接和 iOS 版復(fù)用了所有的 Model 層的代碼毫别。在創(chuàng)業(yè)做猿題庫(kù)客戶端時(shí)娃弓,iOS 和 iPad 版的 Model 層代碼再次被復(fù)用上了。當(dāng)然岛宦,因?yàn)楹蜆I(yè)務(wù)本身的數(shù)據(jù)意義相關(guān)台丛,Model 層的復(fù)用大多數(shù)是在一個(gè)產(chǎn)品內(nèi)部,不太可能像 View 層那樣開(kāi)源給社區(qū)砾肺。
說(shuō)完 View 和 Model 了挽霉,那我們想想 Controller,Controller 有多少可以復(fù)用的变汪?我們寫(xiě)完了一個(gè) Controller 之后侠坎,可以很方便地復(fù)用它嗎?結(jié)論是:非常難復(fù)用裙盾。在某些場(chǎng)景下实胸,我們可能可以用addSubViewController之類(lèi)的方式復(fù)用 Controller,但它的復(fù)用場(chǎng)景還是非常非常少的番官。
如果我們能夠意識(shí)到 Controller 里面的代碼不便于復(fù)用庐完,我們就能知道什么代碼應(yīng)該寫(xiě)在 Controller 里面了,那就是那些不能復(fù)用的代碼徘熔。在我看來(lái)门躯,Controller 里面就只應(yīng)該存放這些不能復(fù)用的代碼,這些代碼包括:
在初始化時(shí)酷师,構(gòu)造相應(yīng)的 View 和 Model讶凉。
監(jiān)聽(tīng) Model 層的事件染乌,將 Model 層的數(shù)據(jù)傳遞到 View 層。
監(jiān)聽(tīng) View 層的事件缀遍,并且將 View 層的事件轉(zhuǎn)發(fā)到 Model 層慕匠。
如果 Controller 只有以上的這些代碼,那么它的邏輯將非常簡(jiǎn)單域醇,而且也會(huì)非常短。
但是蓉媳,我們卻很難做到這一點(diǎn)譬挚,因?yàn)檫€是有很多邏輯我們不知道寫(xiě)在哪里,于是就都寫(xiě)到了 Controller 中了酪呻,那我們接下來(lái)就看看其它邏輯應(yīng)該寫(xiě)在哪里减宣。
MVVM
Model-View-ViewModel 的簡(jiǎn)寫(xiě)。但在我的理解可以是Model-ViewModel-Controller-View
為什么要這樣樣理解呢玩荠?上面的問(wèn)題Controller的代碼處理太多東西漆腌,導(dǎo)致極其難復(fù)用,而且在后期調(diào)整業(yè)務(wù)阶冈,更換UI等事情上也會(huì)較為困難闷尿。
所以我的建議是將Controller的所有業(yè)務(wù)邏輯都應(yīng)該移動(dòng)到ViewModel層上。具體該做些什么呢女坑?
我們可以將網(wǎng)絡(luò)請(qǐng)求的借口填具,及返回的數(shù)據(jù)寫(xiě)在ViewModel里面,ViewModel再通知Controller來(lái)取得相應(yīng)的數(shù)據(jù)匆骗,并顯示在view上劳景。
還可以將邏輯計(jì)算等方法封裝在ViewModel里面,供Controller調(diào)用碉就。當(dāng)然如果這部分計(jì)算復(fù)用性很高盟广,你還可以封裝到其他公用的類(lèi)里面。
而這個(gè)ViewModel將會(huì)是一個(gè)隨時(shí)可以被其他功能模塊調(diào)用的狀態(tài)瓮钥。而且筋量,一個(gè)Controller可以使用一個(gè)或多個(gè)ViewModel。這樣將會(huì)大大提高代碼分復(fù)用性骏庸,及降低后期的維護(hù)毛甲。
MVVM 在使用當(dāng)中,通常還會(huì)利用雙向綁定技術(shù)具被,使得 Model 變化時(shí)玻募,ViewModel 會(huì)自動(dòng)更新,而 ViewModel 變化時(shí)一姿,View 也會(huì)自動(dòng)變化七咧。而這個(gè)過(guò)程我們可以使用KVO和Notification來(lái)實(shí)現(xiàn)跃惫,但這樣并不是最理想和高效的方式,所以我們需要結(jié)合ReactiveCocoa一起使用艾栋。
ReactiveCocoa是一個(gè)函數(shù)式編程(Functional Programming)和響應(yīng)式編程(React Programming)庫(kù)
函數(shù)式編程(Functional Programming)爆存,函數(shù)也變成一等公民了,可以擁有和對(duì)象同樣的功能蝗砾,例如當(dāng)成參數(shù)傳遞先较,當(dāng)作返回值等〉苛福看看 Swift 語(yǔ)言帶來(lái)的眾多函數(shù)式編程的特性闲勺,就你知道這多 Cool 了。
響應(yīng)式編程(React Programming)扣猫,原來(lái)我們基于事件(Event)的處理方式都弱了菜循,現(xiàn)在是基于輸入(在 ReactiveCocoa 里叫 Signal)的處理方式。輸入還可以通過(guò)函數(shù)式編程進(jìn)行各種 Combine 或 Filter申尤,盡顯各種靈活的處理癌幕。
無(wú)狀態(tài)(Stateless),狀態(tài)是函數(shù)的魔鬼昧穿,無(wú)狀態(tài)使得函數(shù)能更好地測(cè)試勺远。
不可修改(Immutable),數(shù)據(jù)都是不可修改的粤咪,使得軟件邏輯簡(jiǎn)單谚中,也可以更好地測(cè)試。
結(jié)合了RAC庫(kù)寥枝,使得我們編寫(xiě)的程序更加簡(jiǎn)潔高效宪塔,維護(hù)性更高。
總結(jié):
使用MVVM編寫(xiě)代碼囊拜,雖然使層次增加了某筐,但是提高了代碼的復(fù)用性及提高了代碼的可維護(hù)性,再結(jié)合RAC就更加牛B閃閃了冠跷。你們覺(jué)得呢南誊?