開發框架(或設計模式)五種(MVC,MVVM,MVCS,MVP,VIPER)區別認識與理解

MVC,衆所周知,就是Model View Controller,是模型(model)-視圖(view)-控制器(controller)的縮寫,一種軟件設計典範,用一種業務邏輯、數據、界面顯示分離的方法組織代碼,將業務邏輯彙集到一個部件裏面,在改進和個性化定製界面及用戶交互的同時,不須要從新編寫業務邏輯。MVC被獨特的發展起來用於映射傳統的輸入、處理和輸出功能在一個邏輯的圖形化用戶界面的結構中。mysql

MVC開始是存在於桌面程序中的,M是指業務模型,V是指用戶界面,C則是控制器,使用MVC的目的是將M和V的實現代碼分離,從而使同一個程序可使用不一樣的表現形式。好比一批統計數據能夠分別用柱狀圖餅圖來表示。C存在的目的則是確保M和V的同步,一旦M改變,V應該同步更新。android

MVC 是一種使用 MVC(Model View Controller 模型-視圖-控制器)設計建立 Web 應用程序的模式:[1]  
  • Model(模型)表示應用程序核心(好比數據庫記錄列表)。
  • View(視圖)顯示數據(數據庫記錄)。
  • Controller(控制器)處理輸入(寫入數據庫記錄)。
MVC 模式同時提供了對 HTML、CSS 和 JavaScript 的徹底控制。
Model(模型)是應用程序中用於處理應用程序數據邏輯的部分。
  一般模型對象負責在數據庫中存取數據。
View(視圖)是應用程序中處理數據顯示的部分。
  一般視圖是依據模型數據建立的。
Controller(控制器)是應用程序中處理用戶交互的部分。
  一般控制器負責從視圖讀取數據,控制用戶輸入,並向模型發送數據。
MVC 分層有助於管理複雜的應用程序,由於您能夠在一個時間內專門關注一個方面。例如,您能夠在不依賴業務邏輯的狀況下專一於視圖設計。同時也讓應用程序的測試更加容易。
MVC 分層同時也簡化了分組開發。不一樣的開發人員可同時開發視圖、控制器邏輯和業務邏輯。

咱們看到的是一個典型的 MVC 設置。Model 呈現數據,View 呈現用戶界面,而 View Controller 調節它二者之間的交互。objective-c

MVC總結:算法

  • 任務均攤–View和Model確實是分開的,可是View和Controller倒是緊密耦合的
  • 可測試性–因爲糟糕的分散性,只能對Model進行測試
  • 易用性–與其餘幾種模式相比最小的代碼量。熟悉的人不少,於是即便對於經驗不那麼豐富的開發者來說維護起來也較爲容易。
MVVM
 

MVVM 是 MVC 模式的一種演進,它主要解決了 ViewController 過於臃腫帶來的不易維護和測試的問題。其中 ViewModel 的主要職責是處理業務邏輯並提供 View 所需的數據,這樣 VC 就不用關心業務,天然也就瘦了下來。ViewModel 只關心業務數據不關心 View,因此不會與 View 產生耦合,也就更方便進行單元測試。sql

View 是一個殼,它所呈現的內容都須要由 ViewModel 來提供,而 View 又不與 ViewModel 直接溝通,這時就須要 ViewController 來作中間的協調者。數據庫

ViewController 持有 View 和 ViewModel,當 VC 初始化時,會讓 ViewModel 去取數據,簡單來講就是調用 VM 的某個獲取數據的方法。數據結構

但大部分國內外資料闡述MVVM的時候都是這樣排布的:View <-> ViewModel <-> Model,形成了MVVM不須要Controller的錯覺,如今彷佛發展成業界開始出現MVVM是不須要Controller的的聲音了。其實MVVM是必定須要Controller的參與的,雖然MVVM在必定程度上弱化了Controller的存在感,而且給Controller作了減負瘦身(這也是MVVM的主要目的)。可是,這並不表明MVVM中不須要Controller,MMVC和MVVM他們之間的關係應該是這樣: 
這裏寫圖片描述多線程

View <-> C <-> ViewModel <-> Model,因此使用MVVM以後,就不須要Controller的說法是不正確的。嚴格來講MVVM實際上是MVCVM。從圖中能夠得知,Controller夾在View和ViewModel之間作的其中一個主要事情就是將View和ViewModel進行綁定。在邏輯上,Controller知道應當展現哪一個View,Controller也知道應當使用哪一個ViewModel,然而View和ViewModel它們之間是互相不知道的,因此Controller就負責控制他們的綁定關係,因此叫Controller/控制器就是這個緣由。 
前面扯了那麼多,其實歸根結底就是一句話:在MVC的基礎上,把C拆出一個ViewModel專門負責數據處理的事情,就是MVVM。而後,爲了讓View和ViewModel之間可以有比較鬆散的綁定關係,因而咱們使用ReactiveCocoa,由於蘋果自己並無提供一個比較適合這種狀況的綁定方法。iOS領域裏KVO,Notification,block,delegate和target-action均可以用來作數據通訊,從而來實現綁定,但都不如ReactiveCocoa提供的RACSignal來的優雅,若是不用ReactiveCocoa,綁定關係可能就作不到那麼鬆散那麼好,但並不影響它仍是MVVM。架構

MVVM如何分工

這裏寫圖片描述
其實你能夠發現MVVM 與 MVP在業務邏輯上很是類似.通常狀況下安卓用MVP要多一些, iOS用MVVM要多一些.mvc

分工總結: 
視圖(View):用戶界面 
模型(Model):數據存儲 
ViewModel:數據請求, 數據處理, 業務邏輯。

MVVM模式特色

  • MVVM將ViewController視做View
  • 在View和Model之間沒有緊密的聯繫,通常的與View是一對一的關係。
  • ViewModel與View之間是雙向交互的
  • 使用 MVVM 最舒服的姿式是搭配如今已經比較成熟的 ReactiveCocoa, 本文最後也推薦了一些關於這方面的博客

MVVM 總結

  • 任務均攤 – 在例子中並非很清晰,可是事實上,MVVM的View要比MVP中的View承擔的責任多。由於前者經過ViewModel的設置綁定來更新狀態,然後者只監聽Presenter的事件但並不會對本身有什麼更新。
  • 可測試性 – ViewModel不知道關於View的任何事情,這容許咱們能夠輕易的測試ViewModel。同時View也能夠被測試,可是因爲屬於UIKit的範疇,對他們的測試一般會被忽略。
  • 易用性 – 在咱們例子中的代碼量和MVP的差很少,可是在實際開發中,咱們必須把View中的事件指向Presenter而且手動的來更新View,若是使用綁定的話,MVVM代碼量將會小的多。

MVCS

蘋果自身就採用的是這種架構思路,從名字也能看出,也是基於MVC衍生出來的一套架構。從概念上來講,它拆分的部分是Model部分,拆出來一個Store。這個Store專門負責數據存取。但從實際操做的角度上講,它拆開的是Controller。

MVCS如何分工

這算是瘦Model的一種方案,瘦Model只是專門用於表達數據,而後存儲、數據處理都交給外面的來作。MVCS使用的前提是,它假設了你是瘦Model,同時數據的存儲和處理都在Controller去作。因此對應到MVCS,它在一開始就是拆分的Controller。由於Controller作了數據存儲的事情,就會變得很是龐大,那麼就把Controller專門負責存取數據的那部分抽離出來,交給另外一個對象去作,這個對象就是Store。這麼調整以後,整個結構也就變成了真正意義上的MVCS。

分工總結: 
視圖(View):用戶界面 
控制器(Controller):業務邏輯及處理 
模型(Model):數據存儲 
存儲器(Store):數據處理邏輯

MVCS是基於瘦Model的一種架構思路,把本來Model要作的不少事情中的其中一部分關於數據存儲的代碼抽象成了Store,在必定程度上下降了Controller的壓力。

關於胖Model和瘦Model

胖Model (Fat Model)

胖Model包含了部分弱業務邏輯。胖Model要達到的目的是,Controller從胖Model這裏拿到數據以後,不用額外作操做或者只要作很是少的操做,就可以將數據直接應用在View上。

FatModel作了這些弱業務以後,Controller就能變得很是skinny,Controller只須要關注強業務代碼就好了。衆所周知,強業務變更的可能性要比弱業務大得多,弱業務相對穩定,因此弱業務塞進Model裏面是沒問題的。另外一方面,弱業務重複出現的頻率要大於強業務,對複用性的要求更高,若是這部分業務寫在Controller,相似的代碼會灑獲得處都是,一旦弱業務有修改(弱業務修改頻率低不表明就沒有修改),這個事情就是一個災難。若是塞到Model裏面去,改一處不少地方就能跟着改,就能避免這場災難。 
然而其缺點就在於,胖Model相對比較難移植,雖然只是包含弱業務,但好歹也是業務,遷移的時候很容易拔出蘿蔔帶出泥。另一點,MVC的架構思想更加傾向於Model是一個Layer,而不是一個Object,不該該把一個Layer應該作的事情交給一個Object去作。最後一點,軟件是會成長的,FatModel頗有可能隨着軟件的成長愈來愈Fat,最終難以維護。

瘦Model(Slim Model)

瘦Model只負責業務數據的表達,全部業務不管強弱一概扔到Controller。瘦Model要達到的目的是,盡一切可能去編寫細粒度Model,而後配套各類helper類或方法來對弱業務作抽象,強業務依舊交給Controller。 
因爲SlimModel跟業務徹底無關,它的數據能夠交給任何一個能處理它數據的Helper或其餘的對象,來完成業務。在代碼遷移的時候獨立性很強,不多會出現拔出蘿蔔帶出泥的狀況。另外,因爲SlimModel只是數據表達,對它進行維護基本上是0成本,軟件膨脹得再厲害,SlimModel也不會大到哪兒去。

缺點就在於,Helper這種作法也不見得很好,這裏有一篇文章批判了這個事情。另外,因爲Model的操做會出如今各類地方,SlimModel在必定程度上違背了DRY(Don’t Repeat Yourself)的思路,Controller仍然不可避免在必定程度上出現代碼膨脹。

MVP

這裏寫圖片描述

這看起來不正是蘋果所提出的MVC方案嗎?確實是的,這種模式的名字叫作MVC,可是,這就是說蘋果的MVC實際上就是MVP了?不,並非這樣的。若是你仔細回憶一下,View是和Controller緊密耦合的,可是MVP的協調器Presenter並無對ViewController的生命週期作任何改變,所以View能夠很容易的被模擬出來。在Presenter中根本沒有和佈局有關的代碼,可是它卻負責更新View的數據和狀態。

MVP如何分工

MVP是第一個如何協調整合三個實際上分離的層次的架構模式,既然咱們不但願View涉及到Model,那麼在顯示的View Controller(其實就是View)中處理這種協調的邏輯就是不正確的,所以咱們須要在其餘地方來作這些事情, 好比用戶輸入操做, 數據請求, 數據處理等等業務邏輯。

分工總結: 
視圖(View):用戶界面 
模型(Model):數據存儲 
展現器(Presenter):數據處理, 業務邏輯。

View和Presenter之間是徹底解耦的,他們經過接口來交互 
View和Presenter是一對一關係,意味着一個Presenter只映射一個View, 且他們之間是能夠雙向交互的。

MVP 總結

    • 任務均攤–咱們將最主要的任務劃分到Presenter和Model,而View的功能較少(雖然上述例子中Model的任務也並很少)。
    • 可測試性–很是好,因爲一個功能簡單的View層,因此測試大多數業務邏輯也變得簡單
    • 易用性–在咱們上邊不切實際的簡單的例子中,代碼量是MVC模式的2倍,但同時MVP的概念卻很是清晰。

VIPER

VIPER 是一個建立 iOS 應用簡明構架的程序。VIPER 能夠是視圖 (View),交互器 (Interactor),展現器 (Presenter),實體 (Entity) 以及路由 (Router) 的首字母縮寫。簡明架構將一個應用程序的邏輯結構劃分爲不一樣的責任層。這使得它更容易隔離依賴項 (如數據庫),也更容易測試各層間的邊界處的交互。

VIPER如何分工

當咱們把VIPER和MV(X)系列做比較時,咱們會在任務均攤性方面發現一些不一樣: 
Model 邏輯經過把實體做爲最小的數據結構轉換到交互器中。 
Controller/Presenter/ViewModel的UI展現方面的職責移到了Presenter中,可是並無數據轉換相關的操做。 
VIPER是第一個經過路由器實現明確的地址導航模式。

這裏寫圖片描述

視圖(View):根據展現器的要求顯示界面,並將用戶輸入反饋給展現器。 
交互器(Interactor):包含由用例指定的業務邏輯。 
展現器(Presenter):包含爲顯示(從交互器接受的內容)作的準備工做的相關視圖邏輯,並對用戶輸入進行反饋(從交互器獲取新數據)。 
實體(Entity):包含交互器要使用的基本模型對象。 
路由(Router):包含用來描述屏幕顯示和顯示順序的導航邏輯。

交互器

交互器在應用中表明着一個獨立的用例。它具備業務邏輯以操縱模型對象(實體)執行特定的任務。交互器中的工做應當獨立與任何用戶界面, 
因爲交互器是一個 PONSO (Plain Old NSObject,普通的 NSObject),它主要包含了邏輯,所以很容易使用 TDD 進行開發。

實體

實體是被交互器操做的模型對象,而且它們只被交互器所操做。交互器永遠不會傳輸實體至表現層 (好比說展現器)。 
實體也應該是 PONSOs。若是你使用 Core Data,最好是將託管對象保持在你的數據層以後,交互器不該與 NSManageObjects 協同工做。

展現器

展現器是一個主要包含了驅動用戶界面的邏輯的 PONSO,它老是知道什麼時候呈現用戶界面。基於其收集來自用戶交互的輸入功能,它能夠在合適的時候更新用戶界面並向交互器發送請求。

視圖

視圖通常是被動的,它一般等待展現器下發須要顯示的內容,而不會向其索取數據。視圖(例如登陸界面的登陸視圖控件)所定義的方法應該容許展現器在高度抽象的層次與之交流。展現器經過內容進行表達,而不關心那些內容所顯示的樣子。展現器不知道 UILabel,UIButton 等的存在,它只知道其中包含的內容以及什麼時候須要顯示。內容如何被顯示是由視圖來進行控制的。 
視圖是一個抽象的接口 (Interface),在 Objective-C 中使用協議被定義。一個 UIViewController 或者它的一個子類會實現視圖協議。

路由

屏幕間的路徑會在交互設計師建立的線框 (wireframes) 裏進行定義。在 VIPER 中,路由是由兩個部分來負責的:展現器和線框。一個線框對象包括 UIWindow,UINavigationController,UIViewController 等部分,它負責建立視圖/視圖控制器並將其裝配到窗口中。 
因爲展現器包含了響應用戶輸入的邏輯,所以它就擁有知曉什麼時候導航至另外一個屏幕以及具體是哪個屏幕的能力。而同時,線框知道如何進行導航。在二者結合起來的狀況下,展現器可使用線框來進行實現導航功能,它們二者一塊兒描述了從一個屏幕至另外一個屏幕的路由過程。

VIPER 特色

數據存儲模塊負責提供實體給交互器。由於交互器要完成業務邏輯,所以它須要從數據存儲中獲取實體並操縱它們,而後將更新後的實體再放回數據存儲中。數據存儲管理實體的持久化,而實體應該對數據庫全然不知,正因如此,實體並不知道如何對本身進行持久化。

交互器一樣不須要知道如何將實體持久化,有時交互器更但願使用一個 data manager 來使其與數據存儲的交互變得容易。Data manager 能夠處理更多的針對存儲的操做,好比建立獲取請求,構建查詢等等。這就使交互器可以將更多的注意力放在應用邏輯上,而沒必要再瞭解實體是如何被彙集或持久化的。

在 iOS 的項目中使用 Core Data 常常比構架自己還容易引發更多爭議。然而,利用 VIPER 來使用 Core Data 將給你帶來使用 Core Data 的史無前例的良好體驗。在持久化數據的工具層面上,Core Data 能夠保持快速存取和低內存佔用方面,簡直是個神器。可是有個很惱人的地方,它會像觸鬚同樣把 NSManagedObjectContext 延伸至你全部的應用實現文件中,特別是那些它們不應待的地方。VIPER 可使 Core Data 待在正確的地方:數據存儲層。

在待辦事項示例中,應用僅有的兩部分知道使用了 Core Data,其一是數據存儲自己,它負責創建 Core Data 堆棧;另外一個是 data manager。Data manager 執行了獲取請求,將數據存儲返回的 NSManagedObject 對象轉換爲標準的 PONSO 模型對象,並傳輸回業務邏輯層。這樣一來,應用程序核心將再也不依賴於 Core Data,附加獲得的好處是,你也不再用擔憂過時數據 (stale) 和沒有良好組織的多線程 NSManagedObjects 來糟蹋你的工做成果了。

VIPER 總結

任務均攤 – 毫無疑問,VIPER是任務劃分中的佼佼者。

可測試性 – 不出意外地,更好的分佈性就有更好的可測試性。

易用性 – 最後你可能已經猜到了維護成本方面的問題。你必須爲很小功能的類寫出大量的接口。

總結

這些架構模式仍是要根據你的項目需求, 項目規模等條件來進行選擇。項目規模越小, 越簡單的話, 就儘可能使用最基本的MVC, 項目再複雜一些的話, 能夠選擇使用MVP, MVVM, 更加繁瑣的項目的話, 那VIPER就能夠排上用場了。你會發現, 這個順序實際上是由簡至繁的, 而爲何要作這樣的選擇呢? 由於他們都是遵循單一責任原則的, 當簡單的項目繁重後, 儘可能開闢出新的角色, 將其工做任務單一化, 這樣就能夠達到項目思路清晰, 易於測試, 易用性高, 維護成本低等要求了。

其實, 你會發現其實這些架構模式都是能夠從MVC的模式下拆分出來的。 我我的認爲, 在作具體的架構設計時,不須要拘泥於MVC、MVVM、VIPER等死規矩, 也能夠本身作一些小的改變, 但要記住只能拆分其它不重要的任務, 並且拆分後的模塊要儘量提升可複用性和抽象度。

相關文章
相關標籤/搜索