iOS架構(gòu)模式(MVC/MVCS/MVP/MVVM/VIPER)

簡(jiǎn)介

談起iOS架構(gòu), 也許你直接想到的就是MVC,MVVM等等. 其實(shí)這是不準(zhǔn)確的, iOS架構(gòu)包含的內(nèi)容有很多, 而上面的這些只是iOS架構(gòu)中的架構(gòu)模式.
那么你在進(jìn)行架構(gòu)設(shè)計(jì)的時(shí)候到底是選擇MVC或者M(jìn)VVM還是選擇VIPER呢? 這就要根據(jù)你的業(yè)務(wù)需求, 項(xiàng)目規(guī)模以及項(xiàng)目未來(lái)的推演預(yù)測(cè)等諸多因素了.
這也是爭(zhēng)議頗多的話題,所以我在這里來(lái)把幾個(gè)主流思想做一個(gè)梳理, 今天就來(lái)說(shuō)一說(shuō) ———– iOS架構(gòu)之架構(gòu)模式.

本文寫(xiě)了些什么?

  • 為什么要關(guān)注架構(gòu)模式
  • 一個(gè)好的架構(gòu)應(yīng)該具備的特點(diǎn)
  • MVC
  • MVCS
  • 關(guān)于胖Model和瘦Model
  • MVP
  • MVVM
  • VIPER
  • 總結(jié)

為什么要關(guān)注架構(gòu)模式

假如你不關(guān)心架構(gòu)模式, 那么總有一天,你會(huì)處在同一個(gè)龐大的類中. 你會(huì)發(fā)現(xiàn)在這樣的條件下, 調(diào)試某些功能或者尋找某個(gè)bug是多么的不易, 你會(huì)花費(fèi)大量的時(shí)間和精力放在這些臃腫的代碼中. 所以, 你應(yīng)該提前想到這些東西, 根據(jù)項(xiàng)目的實(shí)際情況選擇一個(gè)合適的架構(gòu)模式原來(lái)是如此重要.

一個(gè)好的架構(gòu)應(yīng)該具備的特點(diǎn)

一般的, 模塊角色會(huì)有三種:數(shù)據(jù)管理者、數(shù)據(jù)加工者、數(shù)據(jù)展示者. 面對(duì)這些各種各樣的架構(gòu)模式思想,不外乎就是制訂了一個(gè)規(guī)范,規(guī)定了這三個(gè)角色應(yīng)當(dāng)如何進(jìn)行數(shù)據(jù)交換。但一個(gè)號(hào)的架構(gòu)的必要特點(diǎn)是具備如下特點(diǎn):

  • 各角色任務(wù)均衡, 分工明確
  • 測(cè)試可行性高或者說(shuō)易于測(cè)試
  • 維護(hù)成本低
  • 易用性好

MVC

MVC(Model-View-Controller)是最老牌的的思想,其中Model就是作為數(shù)據(jù)管理者,View作為數(shù)據(jù)展示者,Controller作為數(shù)據(jù)加工者,Model和View又都是由Controller來(lái)根據(jù)業(yè)務(wù)需求調(diào)配,所以Controller還負(fù)擔(dān)了一個(gè)數(shù)據(jù)流調(diào)配的功能。

MVC如何分工

模型(Model)的分工:

  • 為ViewController提供數(shù)據(jù)
  • 為ViewController存儲(chǔ)數(shù)據(jù)提供接口
  • 提供經(jīng)過(guò)抽象的業(yè)務(wù)基本組件,供Controller調(diào)度

控制器(Controller)的分工:

  • 管理View Container的生命周期
  • 負(fù)責(zé)生成所有的View實(shí)例,并放入View Container
  • 監(jiān)聽(tīng)來(lái)自View與業(yè)務(wù)有關(guān)的事件,通過(guò)與Model的合作,來(lái)完成對(duì)應(yīng)事件的業(yè)務(wù)。

視圖(View)的分工:

  • 響應(yīng)與業(yè)務(wù)無(wú)關(guān)的事件,并因此引發(fā)動(dòng)畫(huà)效果,點(diǎn)擊反饋(如果合適的話,盡量還是放在View去做)等。
  • 界面元素表達(dá)
這里寫(xiě)圖片描述

分工總結(jié):
視圖(View):用戶界面
控制器(Controller):業(yè)務(wù)邏輯及處理
模型(Model):數(shù)據(jù)存儲(chǔ)

MVC通信特點(diǎn)

這里寫(xiě)圖片描述

1、Model和View永遠(yuǎn)不能相互通信,只能通過(guò)Controller傳遞。
2、Controller可以直接與Model通信(讀寫(xiě)調(diào)用Model),Model通過(guò)Notification和KVO機(jī)制與Controller間接通信。
3、Controller與View通過(guò)Target/Action, delegate和datasource三種模式進(jìn)行通信。通過(guò)這三種模式,View就可以向Controller通信, Action/Target 模式來(lái)讓Controller 監(jiān)聽(tīng)View 觸發(fā)的事件。View又通過(guò)Data source和delegate進(jìn)行數(shù)據(jù)獲取和某些通信操作。

MVC總結(jié)

  • 任務(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)也較為容易。

MVCS

蘋(píng)果自身就采用的是這種架構(gòu)思路,從名字也能看出,也是基于MVC衍生出來(lái)的一套架構(gòu)。從概念上來(lái)說(shuō),它拆分的部分是Model部分,拆出來(lái)一個(gè)Store。這個(gè)Store專門(mén)負(fù)責(zé)數(shù)據(jù)存取。但從實(shí)際操作的角度上講,它拆開(kāi)的是Controller。

MVCS如何分工

這算是瘦Model的一種方案,瘦Model只是專門(mén)用于表達(dá)數(shù)據(jù),然后存儲(chǔ)、數(shù)據(jù)處理都交給外面的來(lái)做。MVCS使用的前提是,它假設(shè)了你是瘦Model,同時(shí)數(shù)據(jù)的存儲(chǔ)和處理都在Controller去做。所以對(duì)應(yīng)到MVCS,它在一開(kāi)始就是拆分的Controller。因?yàn)镃ontroller做了數(shù)據(jù)存儲(chǔ)的事情,就會(huì)變得非常龐大,那么就把Controller專門(mén)負(fù)責(zé)存取數(shù)據(jù)的那部分抽離出來(lái),交給另一個(gè)對(duì)象去做,這個(gè)對(duì)象就是Store。這么調(diào)整之后,整個(gè)結(jié)構(gòu)也就變成了真正意義上的MVCS。

分工總結(jié):
視圖(View):用戶界面
控制器(Controller):業(yè)務(wù)邏輯及處理
模型(Model):數(shù)據(jù)存儲(chǔ)
存儲(chǔ)器(Store):數(shù)據(jù)處理邏輯

MVCS是基于瘦Model的一種架構(gòu)思路,把原本Model要做的很多事情中的其中一部分關(guān)于數(shù)據(jù)存儲(chǔ)的代碼抽象成了Store,在一定程度上降低了Controller的壓力。

關(guān)于胖Model和瘦Model

胖Model (Fat Model)

胖Model包含了部分弱業(yè)務(wù)邏輯。胖Model要達(dá)到的目的是,Controller從胖Model這里拿到數(shù)據(jù)之后,不用額外做操作或者只要做非常少的操作,就能夠?qū)?shù)據(jù)直接應(yīng)用在View上。

FatModel做了這些弱業(yè)務(wù)之后,Controller就能變得非常skinny,Controller只需要關(guān)注強(qiáng)業(yè)務(wù)代碼就行了。眾所周知,強(qiáng)業(yè)務(wù)變動(dòng)的可能性要比弱業(yè)務(wù)大得多,弱業(yè)務(wù)相對(duì)穩(wěn)定,所以弱業(yè)務(wù)塞進(jìn)Model里面是沒(méi)問(wèn)題的。另一方面,弱業(yè)務(wù)重復(fù)出現(xiàn)的頻率要大于強(qiáng)業(yè)務(wù),對(duì)復(fù)用性的要求更高,如果這部分業(yè)務(wù)寫(xiě)在Controller,類似的代碼會(huì)灑得到處都是,一旦弱業(yè)務(wù)有修改(弱業(yè)務(wù)修改頻率低不代表就沒(méi)有修改),這個(gè)事情就是一個(gè)災(zāi)難。如果塞到Model里面去,改一處很多地方就能跟著改,就能避免這場(chǎng)災(zāi)難。
然而其缺點(diǎn)就在于,胖Model相對(duì)比較難移植,雖然只是包含弱業(yè)務(wù),但好歹也是業(yè)務(wù),遷移的時(shí)候很容易拔出蘿卜帶出泥。另外一點(diǎn),MVC的架構(gòu)思想更加傾向于Model是一個(gè)Layer,而不是一個(gè)Object,不應(yīng)該把一個(gè)Layer應(yīng)該做的事情交給一個(gè)Object去做。最后一點(diǎn),軟件是會(huì)成長(zhǎng)的,F(xiàn)atModel很有可能隨著軟件的成長(zhǎng)越來(lái)越Fat,最終難以維護(hù)。

瘦Model(Slim Model)

瘦Model只負(fù)責(zé)業(yè)務(wù)數(shù)據(jù)的表達(dá),所有業(yè)務(wù)無(wú)論強(qiáng)弱一律扔到Controller。瘦Model要達(dá)到的目的是,盡一切可能去編寫(xiě)細(xì)粒度Model,然后配套各種helper類或方法來(lái)對(duì)弱業(yè)務(wù)做抽象,強(qiáng)業(yè)務(wù)依舊交給Controller。
由于SlimModel跟業(yè)務(wù)完全無(wú)關(guān),它的數(shù)據(jù)可以交給任何一個(gè)能處理它數(shù)據(jù)的Helper或其他的對(duì)象,來(lái)完成業(yè)務(wù)。在代碼遷移的時(shí)候獨(dú)立性很強(qiáng),很少會(huì)出現(xiàn)拔出蘿卜帶出泥的情況。另外,由于SlimModel只是數(shù)據(jù)表達(dá),對(duì)它進(jìn)行維護(hù)基本上是0成本,軟件膨脹得再厲害,SlimModel也不會(huì)大到哪兒去。

缺點(diǎn)就在于,Helper這種做法也不見(jiàn)得很好,這里有一篇文章批判了這個(gè)事情。另外,由于Model的操作會(huì)出現(xiàn)在各種地方,SlimModel在一定程度上違背了DRY(Don’t Repeat Yourself)的思路,Controller仍然不可避免在一定程度上出現(xiàn)代碼膨脹。

MVP

這里寫(xiě)圖片描述

這看起來(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)。

MVP如何分工

MVP是第一個(gè)如何協(xié)調(diào)整合三個(gè)實(shí)際上分離的層次的架構(gòu)模式,既然我們不希望View涉及到Model,那么在顯示的View Controller(其實(shí)就是View)中處理這種協(xié)調(diào)的邏輯就是不正確的,因此我們需要在其他地方來(lái)做這些事情, 比如用戶輸入操作, 數(shù)據(jù)請(qǐng)求, 數(shù)據(jù)處理等等業(yè)務(wù)邏輯。

分工總結(jié):
視圖(View):用戶界面
模型(Model):數(shù)據(jù)存儲(chǔ)
展示器(Presenter):數(shù)據(jù)處理, 業(yè)務(wù)邏輯。

View和Presenter之間是完全解耦的,他們通過(guò)接口來(lái)交互
View和Presenter是一對(duì)一關(guān)系,意味著一個(gè)Presenter只映射一個(gè)View, 且他們之間是可以雙向交互的。

MVP 總結(jié)

  • 任務(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的概念卻非常清晰

MVVM

MVVM 是 MVC 模式的一種演進(jìn),它主要解決了 ViewController 過(guò)于臃腫帶來(lái)的不易維護(hù)和測(cè)試的問(wèn)題。其中 ViewModel 的主要職責(zé)是處理業(yè)務(wù)邏輯并提供 View 所需的數(shù)據(jù),這樣 VC 就不用關(guān)心業(yè)務(wù),自然也就瘦了下來(lái)。ViewModel 只關(guān)心業(yè)務(wù)數(shù)據(jù)不關(guān)心 View,所以不會(huì)與 View 產(chǎn)生耦合,也就更方便進(jìn)行單元測(cè)試。

View 是一個(gè)殼,它所呈現(xiàn)的內(nèi)容都需要由 ViewModel 來(lái)提供,而 View 又不與 ViewModel 直接溝通,這時(shí)就需要 ViewController 來(lái)做中間的協(xié)調(diào)者。

ViewController 持有 View 和 ViewModel,當(dāng) VC 初始化時(shí),會(huì)讓 ViewModel 去取數(shù)據(jù),簡(jiǎn)單來(lái)說(shuō)就是調(diào)用 VM 的某個(gè)獲取數(shù)據(jù)的方法。

但大部分國(guó)內(nèi)外資料闡述MVVM的時(shí)候都是這樣排布的:View <-> ViewModel <-> Model,造成了MVVM不需要Controller的錯(cuò)覺(jué),現(xiàn)在似乎發(fā)展成業(yè)界開(kāi)始出現(xiàn)MVVM是不需要Controller的的聲音了。其實(shí)MVVM是一定需要Controller的參與的,雖然MVVM在一定程度上弱化了Controller的存在感,并且給Controller做了減負(fù)瘦身(這也是MVVM的主要目的)。但是,這并不代表MVVM中不需要Controller,MMVC和MVVM他們之間的關(guān)系應(yīng)該是這樣:


這里寫(xiě)圖片描述

View <-> C <-> ViewModel <-> Model,所以使用MVVM之后,就不需要Controller的說(shuō)法是不正確的。嚴(yán)格來(lái)說(shuō)MVVM其實(shí)是MVCVM。從圖中可以得知,Controller夾在View和ViewModel之間做的其中一個(gè)主要事情就是將View和ViewModel進(jìn)行綁定。在邏輯上,Controller知道應(yīng)當(dāng)展示哪個(gè)View,Controller也知道應(yīng)當(dāng)使用哪個(gè)ViewModel,然而View和ViewModel它們之間是互相不知道的,所以Controller就負(fù)責(zé)控制他們的綁定關(guān)系,所以叫Controller/控制器就是這個(gè)原因。
前面扯了那么多,其實(shí)歸根結(jié)底就是一句話:在MVC的基礎(chǔ)上,把C拆出一個(gè)ViewModel專門(mén)負(fù)責(zé)數(shù)據(jù)處理的事情,就是MVVM。然后,為了讓View和ViewModel之間能夠有比較松散的綁定關(guān)系,于是我們使用ReactiveCocoa,因?yàn)樘O(píng)果本身并沒(méi)有提供一個(gè)比較適合這種情況的綁定方法。iOS領(lǐng)域里KVO,Notification,block,delegate和target-action都可以用來(lái)做數(shù)據(jù)通信,從而來(lái)實(shí)現(xiàn)綁定,但都不如ReactiveCocoa提供的RACSignal來(lái)的優(yōu)雅,如果不用ReactiveCocoa,綁定關(guān)系可能就做不到那么松散那么好,但并不影響它還是MVVM。

MVVM如何分工

這里寫(xiě)圖片描述

其實(shí)你可以發(fā)現(xiàn)MVVM 與 MVP在業(yè)務(wù)邏輯上非常相似.一般情況下安卓用MVP要多一些, iOS用MVVM要多一些.

分工總結(jié):
視圖(View):用戶界面
模型(Model):數(shù)據(jù)存儲(chǔ)
ViewModel:數(shù)據(jù)請(qǐng)求, 數(shù)據(jù)處理, 業(yè)務(wù)邏輯。

MVVM模式特點(diǎn)

  • MVVM將ViewController視作View
  • 在View和Model之間沒(méi)有緊密的聯(lián)系,一般的與View是一對(duì)一的關(guān)系。
  • ViewModel與View之間是雙向交互的
  • 使用 MVVM 最舒服的姿勢(shì)是搭配現(xiàn)在已經(jīng)比較成熟的 ReactiveCocoa, 本文最后也推薦了一些關(guān)于這方面的博客

MVVM 總結(jié)

  • 任務(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,如果使用綁定的話,MVVM代碼量將會(huì)小的多。

VIPER

VIPER 是一個(gè)創(chuàng)建 iOS 應(yīng)用簡(jiǎn)明構(gòu)架的程序。VIPER 可以是視圖 (View),交互器 (Interactor),展示器 (Presenter),實(shí)體 (Entity) 以及路由 (Router) 的首字母縮寫(xiě)。簡(jiǎn)明架構(gòu)將一個(gè)應(yīng)用程序的邏輯結(jié)構(gòu)劃分為不同的責(zé)任層。這使得它更容易隔離依賴項(xiàng) (如數(shù)據(jù)庫(kù)),也更容易測(cè)試各層間的邊界處的交互。

VIPER如何分工

當(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)航模式。

這里寫(xiě)圖片描述

視圖(View):根據(jù)展示器的要求顯示界面,并將用戶輸入反饋給展示器。
交互器(Interactor):包含由用例指定的業(yè)務(wù)邏輯。
展示器(Presenter):包含為顯示(從交互器接受的內(nèi)容)做的準(zhǔn)備工作的相關(guān)視圖邏輯,并對(duì)用戶輸入進(jìn)行反饋(從交互器獲取新數(shù)據(jù))。
實(shí)體(Entity):包含交互器要使用的基本模型對(duì)象。
路由(Router):包含用來(lái)描述屏幕顯示和顯示順序的導(dǎo)航邏輯。

交互器

交互器在應(yīng)用中代表著一個(gè)獨(dú)立的用例。它具有業(yè)務(wù)邏輯以操縱模型對(duì)象(實(shí)體)執(zhí)行特定的任務(wù)。交互器中的工作應(yīng)當(dāng)獨(dú)立與任何用戶界面,
由于交互器是一個(gè) PONSO (Plain Old NSObject,普通的 NSObject),它主要包含了邏輯,因此很容易使用 TDD 進(jìn)行開(kāi)發(fā)。

實(shí)體

實(shí)體是被交互器操作的模型對(duì)象,并且它們只被交互器所操作。交互器永遠(yuǎn)不會(huì)傳輸實(shí)體至表現(xiàn)層 (比如說(shuō)展示器)。
實(shí)體也應(yīng)該是 PONSOs。如果你使用 Core Data,最好是將托管對(duì)象保持在你的數(shù)據(jù)層之后,交互器不應(yīng)與 NSManageObjects 協(xié)同工作。

展示器

展示器是一個(gè)主要包含了驅(qū)動(dòng)用戶界面的邏輯的 PONSO,它總是知道何時(shí)呈現(xiàn)用戶界面。基于其收集來(lái)自用戶交互的輸入功能,它可以在合適的時(shí)候更新用戶界面并向交互器發(fā)送請(qǐng)求。

視圖

視圖一般是被動(dòng)的,它通常等待展示器下發(fā)需要顯示的內(nèi)容,而不會(huì)向其索取數(shù)據(jù)。視圖(例如登錄界面的登錄視圖控件)所定義的方法應(yīng)該允許展示器在高度抽象的層次與之交流。展示器通過(guò)內(nèi)容進(jìn)行表達(dá),而不關(guān)心那些內(nèi)容所顯示的樣子。展示器不知道 UILabel,UIButton 等的存在,它只知道其中包含的內(nèi)容以及何時(shí)需要顯示。內(nèi)容如何被顯示是由視圖來(lái)進(jìn)行控制的。
視圖是一個(gè)抽象的接口 (Interface),在 Objective-C 中使用協(xié)議被定義。一個(gè) UIViewController 或者它的一個(gè)子類會(huì)實(shí)現(xiàn)視圖協(xié)議。

路由

屏幕間的路徑會(huì)在交互設(shè)計(jì)師創(chuàng)建的線框 (wireframes) 里進(jìn)行定義。在 VIPER 中,路由是由兩個(gè)部分來(lái)負(fù)責(zé)的:展示器和線框。一個(gè)線框?qū)ο蟀?UIWindow,UINavigationController,UIViewController 等部分,它負(fù)責(zé)創(chuàng)建視圖/視圖控制器并將其裝配到窗口中。
由于展示器包含了響應(yīng)用戶輸入的邏輯,因此它就擁有知曉何時(shí)導(dǎo)航至另一個(gè)屏幕以及具體是哪一個(gè)屏幕的能力。而同時(shí),線框知道如何進(jìn)行導(dǎo)航。在兩者結(jié)合起來(lái)的情況下,展示器可以使用線框來(lái)進(jìn)行實(shí)現(xiàn)導(dǎo)航功能,它們兩者一起描述了從一個(gè)屏幕至另一個(gè)屏幕的路由過(guò)程。

VIPER 特點(diǎn)

數(shù)據(jù)存儲(chǔ)模塊負(fù)責(zé)提供實(shí)體給交互器。因?yàn)榻换テ饕瓿蓸I(yè)務(wù)邏輯,因此它需要從數(shù)據(jù)存儲(chǔ)中獲取實(shí)體并操縱它們,然后將更新后的實(shí)體再放回?cái)?shù)據(jù)存儲(chǔ)中。數(shù)據(jù)存儲(chǔ)管理實(shí)體的持久化,而實(shí)體應(yīng)該對(duì)數(shù)據(jù)庫(kù)全然不知,正因如此,實(shí)體并不知道如何對(duì)自己進(jìn)行持久化。

交互器同樣不需要知道如何將實(shí)體持久化,有時(shí)交互器更希望使用一個(gè) data manager 來(lái)使其與數(shù)據(jù)存儲(chǔ)的交互變得容易。Data manager 可以處理更多的針對(duì)存儲(chǔ)的操作,比如創(chuàng)建獲取請(qǐng)求,構(gòu)建查詢等等。這就使交互器能夠?qū)⒏嗟淖⒁饬Ψ旁趹?yīng)用邏輯上,而不必再了解實(shí)體是如何被聚集或持久化的。

在 iOS 的項(xiàng)目中使用 Core Data 經(jīng)常比構(gòu)架本身還容易引起更多爭(zhēng)議。然而,利用 VIPER 來(lái)使用 Core Data 將給你帶來(lái)使用 Core Data 的前所未有的良好體驗(yàn)。在持久化數(shù)據(jù)的工具層面上,Core Data 可以保持快速存取和低內(nèi)存占用方面,簡(jiǎn)直是個(gè)神器。但是有個(gè)很惱人的地方,它會(huì)像觸須一樣把 NSManagedObjectContext 延伸至你所有的應(yīng)用實(shí)現(xiàn)文件中,特別是那些它們不該待的地方。VIPER 可以使 Core Data 待在正確的地方:數(shù)據(jù)存儲(chǔ)層。

在待辦事項(xiàng)示例中,應(yīng)用僅有的兩部分知道使用了 Core Data,其一是數(shù)據(jù)存儲(chǔ)本身,它負(fù)責(zé)建立 Core Data 堆棧;另一個(gè)是 data manager。Data manager 執(zhí)行了獲取請(qǐng)求,將數(shù)據(jù)存儲(chǔ)返回的 NSManagedObject 對(duì)象轉(zhuǎn)換為標(biāo)準(zhǔn)的 PONSO 模型對(duì)象,并傳輸回業(yè)務(wù)邏輯層。這樣一來(lái),應(yīng)用程序核心將不再依賴于 Core Data,附加得到的好處是,你也再也不用擔(dān)心過(guò)期數(shù)據(jù) (stale) 和沒(méi)有良好組織的多線程 NSManagedObjects 來(lái)糟蹋你的工作成果了。

VIPER 總結(jié)

  • 任務(wù)均攤 – 毫無(wú)疑問(wèn),VIPER是任務(wù)劃分中的佼佼者。
  • 可測(cè)試性 – 不出意外地,更好的分布性就有更好的可測(cè)試性。
  • 易用性 – 最后你可能已經(jīng)猜到了維護(hù)成本方面的問(wèn)題。你必須為很小功能的類寫(xiě)出大量的接口。

總結(jié)

這些架構(gòu)模式還是要根據(jù)你的項(xiàng)目需求, 項(xiàng)目規(guī)模等條件來(lái)進(jìn)行選擇。項(xiàng)目規(guī)模越小, 越簡(jiǎn)單的話, 就盡量使用最基本的MVC, 項(xiàng)目再?gòu)?fù)雜一些的話, 可以選擇使用MVP, MVVM, 更加繁瑣的項(xiàng)目的話, 那VIPER就可以排上用場(chǎng)了。你會(huì)發(fā)現(xiàn), 這個(gè)順序其實(shí)是由簡(jiǎn)至繁的, 而為什么要做這樣的選擇呢? 因?yàn)樗麄兌际亲裱瓎我回?zé)任原則的, 當(dāng)簡(jiǎn)單的項(xiàng)目繁重后, 盡量開(kāi)辟出新的角色, 將其工作任務(wù)單一化, 這樣就可以達(dá)到項(xiàng)目思路清晰, 易于測(cè)試, 易用性高, 維護(hù)成本低等要求了。

其實(shí), 你會(huì)發(fā)現(xiàn)其實(shí)這些架構(gòu)模式都是可以從MVC的模式下拆分出來(lái)的。 我個(gè)人認(rèn)為, 在做具體的架構(gòu)設(shè)計(jì)時(shí),不需要拘泥于MVC、MVVM、VIPER等死規(guī)矩, 也可以自己做一些小的改變, 但要記住只能拆分其它不重要的任務(wù), 而且拆分后的模塊要盡可能提高可復(fù)用性和抽象度。

來(lái)源:http://blog.csdn.net/wangyanchang21/article/details/52050102

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容