在 iOS 中使用 MVC 架構(gòu)感覺(jué)很奇怪? 遷移到MVVM架構(gòu)又懷有疑慮?聽(tīng)說(shuō)過(guò) VIPER 又不確定是否真的值得切換?
相信你會(huì)找到以上問(wèn)題的答案,如果沒(méi)找到請(qǐng)?jiān)谠u(píng)論中指出。
你將要整理出你在 iOS 環(huán)境下所有關(guān)于架構(gòu)模式的知識(shí)。我們將帶領(lǐng)大家簡(jiǎn)要的回顧一些流行的架構(gòu),并且在理論和實(shí)踐上對(duì)它們進(jìn)行比較,通過(guò)一些小的例子深化你的認(rèn)知。如果對(duì)文中提到的一些關(guān)鍵詞有興趣,可以點(diǎn)擊連接去查看更詳細(xì)的內(nèi)容。
掌控設(shè)計(jì)模式可能會(huì)使人上癮,所以要當(dāng)心,你可能會(huì)對(duì)一些問(wèn)題清晰明了,不再像閱讀之前那樣迷惑,比如下面這些問(wèn)題:
誰(shuí)應(yīng)該來(lái)負(fù)責(zé)網(wǎng)絡(luò)請(qǐng)求?Model 還是 Controller ?
應(yīng)該怎樣向一個(gè)新的頁(yè)面的 ViewModel 傳入一個(gè) Model ?
誰(shuí)來(lái)創(chuàng)建一個(gè) VIPER 模塊,是 Router 還是 Presenter ?

為什么要關(guān)注架構(gòu)設(shè)計(jì)?
因?yàn)榧偃缒悴魂P(guān)心架構(gòu),那么總有一天,需要在同一個(gè)龐大的類(lèi)中調(diào)試若干復(fù)雜的事情,你會(huì)發(fā)現(xiàn)在這樣的條件下,根本不可能在這個(gè)類(lèi)中快速的找到以及有效的修改任何bug.當(dāng)然,把這樣的一個(gè)類(lèi)想象為一個(gè)整體是困難的,因此,有可能一些重要的細(xì)節(jié)總會(huì)在這個(gè)過(guò)程中會(huì)被忽略。如果現(xiàn)在的你正是處于這樣一個(gè)開(kāi)發(fā)環(huán)境中,很有可能具體的情況就像下面這樣:
這個(gè)類(lèi)是一個(gè)UIViewController的子類(lèi)
數(shù)據(jù)直接在UIViewController中存儲(chǔ)
UIView類(lèi)幾乎不做任何事情
Model 僅僅是一個(gè)數(shù)據(jù)結(jié)構(gòu)
單元測(cè)試覆蓋不了任何用例
以上這些情況仍舊會(huì)出現(xiàn),即使是你遵循了Apple的指導(dǎo)原則并且實(shí)現(xiàn)了其MVC(模式,所以,大可不必驚慌。Apple所提出的MVC模式存在一些問(wèn)題,我們之后會(huì)詳述。
在此,我們可以定義一個(gè)好的架構(gòu)應(yīng)該具備的特點(diǎn):
任務(wù)均衡分?jǐn)偨o具有清晰角色的實(shí)體
可測(cè)試性通常都來(lái)自與上一條(對(duì)于一個(gè)合適的架構(gòu)是非常容易)
易用性和低成本維護(hù)
為什么采用分布式?
采用分布式可以在我們要弄清楚一些事情的原理時(shí)保持一個(gè)均衡的負(fù)載。如果你認(rèn)為你的開(kāi)發(fā)工作越多,你的大腦越能習(xí)慣復(fù)雜的思維,其實(shí)這是對(duì)的。但是,不能忽略的一個(gè)事實(shí)是,這種思維能力并不是線(xiàn)性增長(zhǎng)的,而且也并不能很快的到達(dá)峰值。所以,能夠戰(zhàn)勝這種復(fù)雜性的最簡(jiǎn)單的方法就是在遵循單一功能原則的前提下,將功能劃分給不同的實(shí)體。
為什么需要易測(cè)性?
其實(shí)這條要求對(duì)于哪些習(xí)慣了單元測(cè)試的人并不是一個(gè)問(wèn)題,因?yàn)樵谔砑恿诵碌奶匦曰蛘咭黾右恍╊?lèi)的復(fù)雜性之后通常會(huì)失效。這就意味著,測(cè)試可以避免開(kāi)發(fā)者在運(yùn)行時(shí)才發(fā)現(xiàn)問(wèn)題----當(dāng)應(yīng)用到達(dá)用戶(hù)的設(shè)備,每一次維護(hù)都需要浪費(fèi)長(zhǎng)達(dá)至少[一周](http://appreviewtimes.com)的時(shí)間才能再次分發(fā)給用戶(hù)。
為什么需要易用性?
這個(gè)問(wèn)題沒(méi)有固定的答案,但值得一提的是,最好的代碼是那些從未寫(xiě)過(guò)的代碼。因此,代碼寫(xiě)的越少,Bug就越少。這意味著希望寫(xiě)更少的代碼不應(yīng)該被單純的解釋為開(kāi)發(fā)者的懶惰,而且也不應(yīng)該因?yàn)槠珢?ài)更聰明的解決方案而忽視了它的維護(hù)開(kāi)銷(xiāo)。
MV(X)系列概要
當(dāng)今我們已經(jīng)有很架構(gòu)設(shè)計(jì)模式方面的選擇:
前三種設(shè)計(jì)模式都把一個(gè)應(yīng)用中的實(shí)體分為以下三類(lèi):
Models--負(fù)責(zé)主要的數(shù)據(jù)或者操作數(shù)據(jù)的數(shù)據(jù)訪(fǎng)問(wèn)層,可以想象 Perspn 和 PersonDataProvider 類(lèi)。
Views--負(fù)責(zé)展示層(GUI),對(duì)于iOS環(huán)境可以聯(lián)想一下以 UI 開(kāi)頭的所有類(lèi)。
Controller/Presenter/ViewModel--負(fù)責(zé)協(xié)調(diào) Model 和 View,通常根據(jù)用戶(hù)在View上的動(dòng)作在Model上作出對(duì)應(yīng)的更改,同時(shí)將更改的信息返回到View上。
將實(shí)體進(jìn)行劃分給我們帶來(lái)了以下好處:
更好的理解它們之間的關(guān)系
復(fù)用(尤其是對(duì)于View和Model)
獨(dú)立的測(cè)試
讓我們開(kāi)始了解MV(X)系列,之后再返回到VIPER模式。
MVC的過(guò)去
在我們探討Apple的MVC模式之前,我們來(lái)看下傳統(tǒng)的MVC模式。

傳統(tǒng)的MVC
在這里,View并沒(méi)有任何界限,僅僅是簡(jiǎn)單的在Controller中呈現(xiàn)出Model的變化。想象一下,就像網(wǎng)頁(yè)一樣,在點(diǎn)擊了跳轉(zhuǎn)到某個(gè)其他頁(yè)面的連接之后就會(huì)完全的重新加載頁(yè)面。盡管在iOS平臺(tái)上實(shí)現(xiàn)這這種MVC模式是沒(méi)有任何難度的,但是它并不會(huì)為我們解決架構(gòu)問(wèn)題帶來(lái)任何裨益。因?yàn)樗旧硪彩?,三個(gè)實(shí)體間相互都有通信,而且是緊密耦合的。這很顯然會(huì)大大降低了三者的復(fù)用性,而這正是我們不愿意看到的。鑒于此我們不再給出例子。
“傳統(tǒng)的MVC架構(gòu)不適用于當(dāng)下的iOS開(kāi)發(fā)”
蘋(píng)果推薦的MVC--愿景

Cocoa MVC
由于Controller是一個(gè)介于View 和 Model之間的協(xié)調(diào)器,所以View和Model之間沒(méi)有任何直接的聯(lián)系。Controller是一個(gè)最小可重用單元,這對(duì)我們來(lái)說(shuō)是一個(gè)好消息,因?yàn)槲覀兛傄乙粋€(gè)地方來(lái)寫(xiě)邏輯復(fù)雜度較高的代碼,而這些代碼又不適合放在Model中。
理論上來(lái)講,這種模式看起來(lái)非常直觀,但你有沒(méi)有感到哪里有一絲詭異?你甚至聽(tīng)說(shuō)過(guò),有人將MVC的縮寫(xiě)展開(kāi)成(Massive View Controller),更有甚者,為View controller減負(fù)也成為iOS開(kāi)發(fā)者面臨的一個(gè)重要話(huà)題。如果蘋(píng)果繼承并且對(duì)MVC模式有一些進(jìn)展,所有這些為什么還會(huì)發(fā)生?
蘋(píng)果推薦的MVC--事實(shí)

Realistic Cocoa MVC
Cocoa的MVC模式驅(qū)使人們寫(xiě)出臃腫的視圖控制器,因?yàn)樗鼈兘?jīng)常被混雜到View的生命周期中,因此很難說(shuō)View和ViewController是分離的。盡管仍可以將業(yè)務(wù)邏輯和數(shù)據(jù)轉(zhuǎn)換到Model,但是大多數(shù)情況下當(dāng)需要為View減負(fù)的時(shí)候我們卻無(wú)能為力了,View的最大的任務(wù)就是向Controller傳遞用戶(hù)動(dòng)作事件。ViewController最終會(huì)承擔(dān)一切代理和數(shù)據(jù)源的職責(zé),還負(fù)責(zé)一些分發(fā)和取消網(wǎng)絡(luò)請(qǐng)求以及一些其他的任務(wù),因此它的名字的由來(lái)...你懂的。
你可能會(huì)看見(jiàn)過(guò)很多次這樣的代碼:

這個(gè)cell,正是由View直接來(lái)調(diào)用Model,所以事實(shí)上MVC的原則已經(jīng)違背了,但是這種情況是一直發(fā)生的甚至于人們不覺(jué)得這里有哪些不對(duì)。如果嚴(yán)格遵守MVC的話(huà),你會(huì)把對(duì)cell的設(shè)置放在 Controller 中,不向View傳遞一個(gè)Model對(duì)象,這樣就會(huì)大大增加Controller的體積。
“Cocoa 的MVC被寫(xiě)成Massive View Controller 是不無(wú)道理的?!?/b>
直到進(jìn)行單元測(cè)試的時(shí)候才會(huì)發(fā)現(xiàn)問(wèn)題越來(lái)越明顯。因?yàn)槟愕腣iewController和View是緊密耦合的,對(duì)它們進(jìn)行測(cè)試就顯得很艱難--你得有足夠的創(chuàng)造性來(lái)模擬View和它們的生命周期,在以這樣的方式來(lái)寫(xiě)View Controller的同時(shí),業(yè)務(wù)邏輯的代碼也逐漸被分散到View的布局代碼中去。
我們看下一些簡(jiǎn)單的例子:

“MVC可以在一個(gè)正在顯示的ViewController中實(shí)現(xiàn)”
這段代碼看起來(lái)可測(cè)試性并不強(qiáng),我們可以把和greeting相關(guān)的都放到GreetingModel中然后分開(kāi)測(cè)試,但是這樣我們就無(wú)法通過(guò)直接調(diào)用在GreetingViewController中的UIView的方法(viewDidLoad和didTapButton方法)來(lái)測(cè)試頁(yè)面的展示邏輯了,因?yàn)橐坏┱{(diào)用則會(huì)使整個(gè)頁(yè)面都變化,這對(duì)單元測(cè)試來(lái)講并不是什么好消息。
事實(shí)上,在單獨(dú)一個(gè)模擬器中(比如iPhone 4S)加載并測(cè)試UIView并不能保證在其他設(shè)備中也能正常工作,因此我建議在單元測(cè)試的Target的設(shè)置下移除"Host Application"項(xiàng),并且不要在模擬器中測(cè)試你的應(yīng)用。
“View和Controller的接口并不適合單元測(cè)試?!?/b>
以上所述,似乎Cocoa MVC 看起來(lái)是一個(gè)相當(dāng)差的架構(gòu)方案。我們來(lái)重新評(píng)估一下文章開(kāi)頭我們提出的MVC一系列的特征:
任務(wù)均攤--View和Model確實(shí)是分開(kāi)的,但是View和Controller卻是緊密耦合的
可測(cè)試性--由于糟糕的分散性,只能對(duì)Model進(jìn)行測(cè)試
易用性--與其他幾種模式相比最小的代碼量。熟悉的人很多,因而即使對(duì)于經(jīng)驗(yàn)不那么豐富的開(kāi)發(fā)者來(lái)講維護(hù)起來(lái)也較為容易。
如果你不想在架構(gòu)選擇上投入更多精力,那么Cocoa MVC無(wú)疑是最好的方案,而且你會(huì)發(fā)現(xiàn)一些其他維護(hù)成本較高的模式對(duì)于你所開(kāi)發(fā)的小的應(yīng)用是一個(gè)致命的打擊。
“就開(kāi)發(fā)速度而言,Cocoa MVC是最好的架構(gòu)選擇方案?!?/b>
MVP實(shí)現(xiàn)了Cocoa的MVC的愿景

Passive View variant of MVP
這看起來(lái)不正是蘋(píng)果所提出的MVC方案嗎?確實(shí)是的,這種模式的名字叫做MVC,但是,這就是說(shuō)蘋(píng)果的MVC實(shí)際上就是MVP了?不,并不是這樣的。如果你仔細(xì)回憶一下,View是和Controller緊密耦合的,但是MVP的協(xié)調(diào)器Presenter并沒(méi)有對(duì)ViewController的生命周期做任何改變,因此View可以很容易的被模擬出來(lái)。在Presenter中根本沒(méi)有和布局有關(guān)的代碼,但是它卻負(fù)責(zé)更新View的數(shù)據(jù)和狀態(tài)。
“假如告訴你UIViewController就是View呢?”
就MVP而言,UIViewController的子類(lèi)實(shí)際上就是Views并不是Presenters。這點(diǎn)區(qū)別使得這種模式的可測(cè)試性得到了極大的提高,付出的代價(jià)是開(kāi)發(fā)速度的一些降低,因?yàn)楸仨氁鲆恍┦謩?dòng)的數(shù)據(jù)和事件綁定,從下例中可以看出:


關(guān)于整合問(wèn)題的重要說(shuō)明
MVP是第一個(gè)如何協(xié)調(diào)整合三個(gè)實(shí)際上分離的層次的架構(gòu)模式,既然我們不希望View涉及到Model,那么在顯示的View Controller(其實(shí)就是View)中處理這種協(xié)調(diào)的邏輯就是不正確的,因此我們需要在其他地方來(lái)做這些事情。例如,我們可以做基于整個(gè)App范圍內(nèi)的路由服務(wù),由它來(lái)負(fù)責(zé)執(zhí)行協(xié)調(diào)任務(wù),以及View到View的展示。這個(gè)出現(xiàn)并且必須處理的問(wèn)題不僅僅是在MVP模式中,同時(shí)也存在于以下集中方案中。
我們來(lái)看下MVP模式下的三個(gè)特性的分析:
任務(wù)均攤--我們將最主要的任務(wù)劃分到Presenter和Model,而View的功能較少(雖然上述例子中Model的任務(wù)也并不多)。
可測(cè)試性--非常好,由于一個(gè)功能簡(jiǎn)單的View層,所以測(cè)試大多數(shù)業(yè)務(wù)邏輯也變得簡(jiǎn)單
易用性--在我們上邊不切實(shí)際的簡(jiǎn)單的例子中,代碼量是MVC模式的2倍,但同時(shí)MVP的概念卻非常清晰
“iOS 中的MVP意味著可測(cè)試性強(qiáng)、代碼量大。”
MVP--綁定和信號(hào)
還有一些其他形態(tài)的MVP--監(jiān)控控制器的MVP。
這個(gè)變體包含了View和Model之間的直接綁定,但是Presenter仍然來(lái)管理來(lái)自View的動(dòng)作事件,同時(shí)也能勝任對(duì)View的更新。

Supervising Presenter variant of the MVP
但是我們之前就了解到,模糊的職責(zé)劃分是非常糟糕的,更何況將View和Model緊密的聯(lián)系起來(lái)。這和Cocoa的桌面開(kāi)發(fā)的原理有些相似。
和傳統(tǒng)的MVC一樣,寫(xiě)這樣的例子沒(méi)有什么價(jià)值,故不再給出。
MVVM--最新且是最偉大的MV(X)系列的一員
MVVM架構(gòu)是MV(X)系列最新的一員,因此讓我們希望它已經(jīng)考慮到MV(X)系列中之前已經(jīng)出現(xiàn)的問(wèn)題。
從理論層面來(lái)講MVVM看起來(lái)不錯(cuò),我們已經(jīng)非常熟悉View和Model,以及Meditor,在MVVM中它是View Model。

MVVM
它和MVP模式看起來(lái)非常像:
MVVM將ViewController視作View
在View和Model之間沒(méi)有緊密的聯(lián)系
此外,它還有像監(jiān)管版本的MVP那樣的綁定功能,但這個(gè)綁定不是在View和Model之間而是在View和ViewModel之間。
那么問(wèn)題來(lái)了,在iOS中ViewModel實(shí)際上代表什么?它基本上就是UIKit下的每個(gè)控件以及控件的狀態(tài)。ViewModel調(diào)用會(huì)改變Model同時(shí)會(huì)將Model的改變更新到自身并且因?yàn)槲覀兘壎薞iew和ViewModel,第一步就是相應(yīng)的更新?tīng)顟B(tài)。
綁定
我在MVP部分已經(jīng)提到這點(diǎn)了,但是該部分我們?nèi)詴?huì)繼續(xù)討論。
如果我們自己不想自己實(shí)現(xiàn),那么我們有兩種選擇:
基于KVO的綁定庫(kù)如RZDataBinding和SwiftBond
完全的函數(shù)響應(yīng)式編程,比如像ReactiveCocoa、RxSwift或者PromiseKit
事實(shí)上,尤其是最近,你聽(tīng)到MVVM就會(huì)想到ReactiveCoca,反之亦然。盡管通過(guò)簡(jiǎn)單的綁定來(lái)使用MVVM是可實(shí)現(xiàn)的,但是ReactiveCocoa卻能更好的發(fā)揮MVVM的特點(diǎn)。
但是關(guān)于這個(gè)框架有一個(gè)不得不說(shuō)的事實(shí):強(qiáng)大的能力來(lái)自于巨大的責(zé)任。當(dāng)你開(kāi)始使用Reactive的時(shí)候有很大的可能就會(huì)把事情搞砸。換句話(huà)來(lái)說(shuō)就是,如果發(fā)現(xiàn)了一些錯(cuò)誤,調(diào)試出這個(gè)bug可能會(huì)花費(fèi)大量的時(shí)間,看下函數(shù)調(diào)用棧:

Reactive Debugging
在我們簡(jiǎn)單的例子中,F(xiàn)RF框架和KVO被過(guò)渡禁用,取而代之地我們直接去調(diào)用showGreeting方法更新ViewModel,以及通過(guò)greetingDidChange 回調(diào)函數(shù)使用屬性。


讓我們?cè)賮?lái)看看關(guān)于三個(gè)特性的評(píng)估:
任務(wù)均攤 -- 在例子中并不是很清晰,但是事實(shí)上,MVVM的View要比MVP中的View承擔(dān)的責(zé)任多。因?yàn)榍罢咄ㄟ^(guò)ViewModel的設(shè)置綁定來(lái)更新?tīng)顟B(tài),而后者只監(jiān)聽(tīng)Presenter的事件但并不會(huì)對(duì)自己有什么更新。
可測(cè)試性 -- ViewModel不知道關(guān)于View的任何事情,這允許我們可以輕易的測(cè)試ViewModel。同時(shí)View也可以被測(cè)試,但是由于屬于UIKit的范疇,對(duì)他們的測(cè)試通常會(huì)被忽略。
易用性 -- 在我們例子中的代碼量和MVP的差不多,但是在實(shí)際開(kāi)發(fā)中,我們必須把View中的事件指向Presenter并且手動(dòng)的來(lái)更新View,如果使用綁定的話(huà),MVVM代碼量將會(huì)小的多。
“MVVM很誘人,因?yàn)樗狭松鲜龇椒ǖ膬?yōu)點(diǎn),并且由于在View層的綁定,它并不需要其他附加的代碼來(lái)更新View,盡管這樣,可測(cè)試性依然很強(qiáng)?!?/b>
VIPER--把LEGO建筑經(jīng)驗(yàn)遷移到iOS app的設(shè)計(jì)
VIPER是我們最后要介紹的,由于不是來(lái)自于MV(X)系列,它具備一定的趣味性。
迄今為止,劃分責(zé)任的粒度是很好的選擇。VIPER在責(zé)任劃分層面進(jìn)行了迭代,VIPER分為五個(gè)層次:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?VIPER
交互器-- 包括關(guān)于數(shù)據(jù)和網(wǎng)絡(luò)請(qǐng)求的業(yè)務(wù)邏輯,例如創(chuàng)建一個(gè)實(shí)體(數(shù)據(jù)),或者從服務(wù)器中獲取一些數(shù)據(jù)。為了實(shí)現(xiàn)這些功能,需要使用服務(wù)、管理器,但是他們并不被認(rèn)為是VIPER架構(gòu)內(nèi)的模塊,而是外部依賴(lài)。
展示器-- 包含UI層面的業(yè)務(wù)邏輯以及在交互器層面的方法調(diào)用。
實(shí)體-- 普通的數(shù)據(jù)對(duì)象,不屬于數(shù)據(jù)訪(fǎng)問(wèn)層次,因?yàn)閿?shù)據(jù)訪(fǎng)問(wèn)屬于交互器的職責(zé)。
路由器-- 用來(lái)連接VIPER的各個(gè)模塊。
基本上,VIPER模塊可以是一個(gè)屏幕或者用戶(hù)使用應(yīng)用的整個(gè)過(guò)程--想想認(rèn)證過(guò)程,可以由一屏完成或者需要幾步才能完成,你的模塊期望是多大的,這取決于你。
當(dāng)我們把VIPER和MV(X)系列作比較時(shí),我們會(huì)在任務(wù)均攤性方面發(fā)現(xiàn)一些不同:
Model邏輯通過(guò)把實(shí)體作為最小的數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)換到交互器中。
Controller/Presenter/ViewModel的UI展示方面的職責(zé)移到了Presenter中,但是并沒(méi)有數(shù)據(jù)轉(zhuǎn)換相關(guān)的操作。
VIPER是第一個(gè)通過(guò)路由器實(shí)現(xiàn)明確的地址導(dǎo)航模式。
“找到一個(gè)適合的方法來(lái)實(shí)現(xiàn)路由對(duì)于iOS應(yīng)用是一個(gè)挑戰(zhàn),MV(X)系列避開(kāi)了這個(gè)問(wèn)題?!?/b>
例子中并不包含路由和模塊之間的交互,所以和MV(X)系列部分架構(gòu)一樣不再給出例子。


讓我們?cè)賮?lái)評(píng)估一下特性:
任務(wù)均攤 -- 毫無(wú)疑問(wèn),VIPER是任務(wù)劃分中的佼佼者。
可測(cè)試性 -- 不出意外地,更好的分布性就有更好的可測(cè)試性。
易用性 -- 最后你可能已經(jīng)猜到了維護(hù)成本方面的問(wèn)題。你必須為很小功能的類(lèi)寫(xiě)出大量的接口。
什么是LEGO
當(dāng)使用VIPER時(shí),你的感覺(jué)就像是用樂(lè)高積木來(lái)搭建一個(gè)城堡,這也是一個(gè)表明當(dāng)前存在一些問(wèn)題的信號(hào)。可能現(xiàn)在就應(yīng)用VIPER架構(gòu)還為時(shí)過(guò)早,考慮一些更為簡(jiǎn)單的模式可能會(huì)更好。一些人會(huì)忽略這些問(wèn)題,大材小用。假定他們篤信VIPER架構(gòu)會(huì)在未來(lái)給他們的應(yīng)用帶來(lái)一些好處,雖然現(xiàn)在維護(hù)起來(lái)確實(shí)是有些不合理。如果你也持這樣的觀點(diǎn),我為你推薦Generamba這個(gè)用來(lái)搭建VIPER架構(gòu)的工具。雖然我個(gè)人感覺(jué),使用起來(lái)就像加農(nóng)炮的自動(dòng)瞄準(zhǔn)系統(tǒng),而不是簡(jiǎn)單的像投石器那樣的簡(jiǎn)單的拋擲。
總結(jié)
我們了解了集中架構(gòu)模式,希望你已經(jīng)找到了到底是什么在困擾你。毫無(wú)疑問(wèn)通過(guò)閱讀本篇文章,你已經(jīng)了解到其實(shí)并沒(méi)有完全的銀彈。所以選擇架構(gòu)是一個(gè)根據(jù)實(shí)際情況具體分析利弊的過(guò)程。
因此,在同一個(gè)應(yīng)用中包含著多種架構(gòu)。比如,你開(kāi)始的時(shí)候使用MVC,然后突然意識(shí)到一個(gè)頁(yè)面在MVC模式下的變得越來(lái)越難以維護(hù),然后就切換到MVVM架構(gòu),但是僅僅針對(duì)這一個(gè)頁(yè)面。并沒(méi)有必要對(duì)哪些MVC模式下運(yùn)轉(zhuǎn)良好的頁(yè)面進(jìn)行重構(gòu),因?yàn)槎呤强梢圆⒋娴摹?/p>

上圖為2017年最新的視頻教程資料,搜索235再填上214最后輸入9755加我好友私聊我上傳視頻教程,有什么不懂的也可以來(lái)私聊問(wèn)我。
不定時(shí)更新中。
如果你能明白這些視頻資料的好差,那么你也算是入行了,底層和中高層就是這一步之差。