MVC、MVP、MVVM

iOS MVC 示意圖

這裏寫圖片描述

MVC 的幾個明顯的特徵和體現:

1、View 上面顯示什麼東西,取決於 Model。Model和View永遠不能相互通信,只能通過Controller傳遞。

2、Model通過Notification和KVO機制與Controller間接通信。只要 Model 數據改了,View 的顯示狀態會跟着更改。

3、Controller可以直接與View對話(通過outlet,直接操作View,outlet直接對應到View中的控件),View通過 action向Controller報告事件的發生(如用戶Touch我了)。Controller是View的直接數據源(數據很可能是 Controller從Model中取得的)。有時候Controller需要實時監控View的狀態,這時Controller會通過protocol將其自身設爲View的delegate,這樣當View will change、should change、did change 的時候Controller也會接到相應通知。
View不存儲數據,但View可以通過協議獲取Controller而不是Model中的數據用來展示。
Control 負責初始化 Model,並將 Model 傳遞給 View 去解析展示。

1)Modal 模型對象:

模型對象封裝了應用程序的數據,並定義操控和處理該數據的邏輯和運算。例如,模型對象可能是表示商品數據 list。用戶在視圖層中所進行的創建或修改數據的操作,通過控制器對象傳達出去,最終會創建或更新模型對象。模型對象更改時(例如通過網絡連接接收到新數據),它通知控制器對象,控制器對象更新相應的視圖對象。

2)View 視圖對象:

視圖對象是應用程序中用戶可以看見的對象。視圖對象知道如何將自己繪製出來,可能對用戶的操作作出響應。視圖對象的主要目的就是顯示來自應用程序模型對象的數據,並使該數據可被編輯。儘管如此,在 MVC 應用程序中,視圖對象通常與模型對象分離。

在iOS應用程序開發中,所有的控件、窗口等都繼承自 UIView,對應 MVC 中的 V。UIView 及其子類主要負責 UI 的實現,而 UIView 所產生的事件都可以採用委託的方式,交給 UIViewController 實現。

3)Controller 控制器對象:

在應用程序的一個或多個視圖對象和一個或多個模型對象之間,控制器對象充當媒介。控制器對象因此是同步管道程序,通過它,視圖對象瞭解模型對象的更改,反之亦然。控制器對象還可以爲應用程序執行設置和協調任務,並管理其他對象的生命週期。

控制器對象解釋在視圖對象中進行的用戶操作,並將新的或更改過的數據傳達給模型對象。模型對象更改時,一個控制器對象會將新的模型數據傳達給視圖對象,以便視圖對象可以顯示它。

對於不同的 UIView,有相應的 UIViewController,對應 MVC 中的 C。例如在 iOS 上常用的 UITableView,它所對應的 Controller 就是UITableViewController。

蘋果推薦的 MVC – 願景

這裏寫圖片描述

Cocoa MVC

1、由於 Controller 是一個介於 View 和 Model 之間的協調器,所以 View 和 Model 之間沒有任何直接的聯繫。Controller 是一個最小可重用單元,這對我們來說是一個好消息,因爲我們總要找一個地方來寫邏輯複雜度較高的代碼,而這些代碼又不適合放在 Model 中。

2、理論上來講,這種模式看起來非常直觀,但你有沒有感到哪裏有一絲詭異?你甚至聽說過,有人將 MVC 的縮寫展開成 (Massive View Controller),更有甚者,爲 View controller 減負也成爲 iOS 開發者面臨的一個重要話題。如果蘋果繼承並且對 MVC 模式有一些進展,所有這些爲什麼還會發生?

蘋果推薦的 MVC – 事實

這裏寫圖片描述

Realistic Cocoa MVC

Cocoa 的 MVC 模式驅使人們寫出臃腫的視圖控制器,因爲它們經常被混雜到 View 的生命週期中,因此很難說 View 和 ViewController 是分離的。儘管仍可以將業務邏輯和數據轉換到 Model,但是大多數情況下當需要爲 View 減負的時候我們卻無能爲力了,View 的最大的任務就是向 Controller 傳遞用戶動作事件。ViewController 不再承擔一切代理和數據源的職責,通常只負責一些分發和取消網絡請求以及一些其他的任務。

你可能會看見過很多次這樣的代碼:

BookModel *bookModel = [myDataArray objectAtIndex:indexPath.row];
[cell configWithModel:bookModel];

1、這個 cell,正是由 View 直接來調用 Model,所以事實上 MVC 的原則已經違背了,但是這種情況是一直髮生的甚至於人們不覺得這裏有哪些不對。如果嚴格遵守 MVC 的話,你會把對 cell 的設置放在 Controller 中,不向 View 傳遞一個 Model 對象,這樣就會大大減少 Controller 的體積。Cocoa 的 MVC 被寫成 Massive View Controller 是不無道理的。

2、直到進行單元測試的時候纔會發現問題越來越明顯。因爲你的 ViewController 和 View 是緊密耦合的,對它們進行測試就顯得很艱難–你得有足夠的創造性來模擬 View 和它們的生命週期,在以這樣的方式來寫 View Controller 的同時,業務邏輯的代碼也逐漸被分散到 View 的佈局代碼中去。

MVC 自身的不足:

1)MVC 在現實應用中的不足:

在 MVC 模式中 view 將用戶交互通知給控制器。view 的控制器通過更新 Model 來反應狀態的改變。Model(通常使用 Key-Value-Observation)通知控制器來更新他們負責的 view。大多數 iOS 應用程序的代碼使用這種方式來組織。
2)愈發笨重的 Controller:

在傳統的 app 中模型數據一般都很簡單,不涉及到複雜的業務數據邏輯處理,客戶端開發受限於它自身運行的的平臺終端,這一點註定使移動端不像 PC 前端那樣能夠處理大量的複雜的業務場景。然而隨着移動平臺的各種深入,我們不得不考慮這個問題。傳統的 Model 數據大多來源於網絡數據,拿到網絡數據後客戶端要做的事情就是將數據直接按照順序畫在界面上。隨着業務的越來越來的深入,我們依賴的 service 服務可能在大多時間無法第一時間滿足客戶端需要的數據需求,移動端愈發的要自行處理一部分邏輯計算操作。這個時間一慣的做法是在控制器中處理,最終導致了控制器成了垃圾箱,越來越不可維護。

控制器 Controller 是 app 的 “膠水代碼”,協調模型和視圖之間的所有交互。控制器負責管理他們所擁有的視圖的視圖層次結構,還要響應視圖的 loading、appearing、disappearing 等等,同時往往也會充滿我們不願暴露的 Model 的模型邏輯以及不願暴露給視圖的業務邏輯。這引出了第一個關於 MVC 的問題…

視圖 view 通常是 UIKit 控件(component,這裏根據習慣譯爲控件)或者編碼定義的 UIKit 控件的集合。進入 .xib 或者 Storyboard 會發現一個 app、Button、Label 都是由這些可視化的和可交互的控件組成。View 不應該直接引用 Model,並且僅僅通過 IBAction 事件引用 controller。業務邏輯很明顯不歸入 view,視圖本身沒有任何業務。

厚重的 View Controller 由於大量的代碼被放進 viewcontroller,導致他們變的相當臃腫。在 iOS 中有的 view controller 裏綿延成千上萬行代碼的事並不是前所未見的。這些超重 app 的突出情況包括:厚重的 View Controller 很難維護(由於其龐大的規模);包含幾十個屬性,使他們的狀態難以管理;遵循許多協議(protocol),導致協議的響應代碼和 controller 的邏輯代碼混淆在一起。

厚重的 view controller 很難測試,不管是手動測試或是使用單元測試,因爲有太多可能的狀態。將代碼分解成更小的多個模塊通常是件好事。

3)太過於輕量級的 Model:

早期的 Model 層,其實就是如果數據有幾個屬性,就定義幾個屬性,ARC 普及以後我們在 Model 層的實現文件中基本上看不到代碼(無需再手動管理釋放變量,Model 既沒有複雜的業務處理,也沒有對象的構造,基本上 .m 文件中的代碼普遍是空的);同時與控制器的代碼越來厚重形成強烈的反差,這一度讓人不禁對現有的開發設計構思有所懷疑。
4)遺失的網絡邏輯:

蘋果使用的 MVC 的定義是這麼說的:所有的對象都可以被歸類爲一個 Model,一個 view,或是一個控制器。就這些,那麼把網絡代碼放哪裏?和一個 API 通信的代碼應該放在哪兒?

你可能試着把它放在 Model 對象裏,但是也會很棘手,因爲網絡調用應該使用異步,這樣如果一個網絡請求比持有它的 Model 生命週期更長,事情將變的複雜。顯然也不應該把網絡代碼放在 view 裏,因此只剩下控制器了。這同樣是個壞主意,因爲這加劇了厚重控制器的問題。那麼應該放在那裏呢?顯然 MVC 的 3 大組件根本沒有適合放這些代碼的地方。

5)較差的可測試性

MVC 的另一個大問題是,它不鼓勵開發人員編寫單元測試。由於控制器混合了視圖處理邏輯和業務邏輯,分離這些成分的單元測試成了一個艱鉅的任務。大多數人選擇忽略這個任務,那就是不做任何測試。

上文提到了控制器可以管理視圖的層次結構;控制器有一個 “view” 屬性,並且可以通過 IBOutlet 訪問視圖的任何子視圖。當有很多 outlet 時這樣做不易於擴展,在某種意義上,最好不要使用子視圖控制器(child view controller)來幫助管理子視圖。在這裏有多個模糊的標準,似乎沒有人能完全達成一致。貌似無論如何,view 和對應的 controller 都緊緊的耦合在一起,總之,還是會把它們當成一個組件來對待。Apple 提供的這個組件一度以來在某種程度誤導了大多初學者,初學者將所有的視圖全部拖到 xib 中,連接大量的 IBoutLet 輸出口屬性,都是一些列問題。

MVP

C和P的差別

MVP其實兩種的:

1、Passive View
2、Supervising Controller

網上絕對部分談論MVP的文章談論的其實都是Passive View,這裏放上一張Passive View的示意圖:
這裏寫圖片描述

MVP: the view is in charge. The view, in most cases, creates its presenter. The presenter will interact with the model and manipulate the view through an interface. The view will sometimes interact with the presenter, usually through some interface. This comes down to implementation; do you want the view to call methods on the presenter or do you want the view to have events the presenter listens to? It boils down to this: The view knows about the presenter. The view delegates to the presenter.

view負責。大部分情況下,view創建它自己的presenter。presenter通過接口和model相互作用然後操作這個view。view通常會通過一些接口有時會和presenter相互作用。歸結起來實現:你想讓view在presenter上調用方法或者想讓view監聽presenter上的一些事件嗎?歸結起來:view瞭解presenter。view是presenter的代理。

MVC: the controller is in charge. The controller is created or accessed based on some event/request. The controller then creates the appropriate view and interacts with the model to further configure the view. It boils down to: the controller creates and manages the view; the view is slave to the controller. The view does not know about the controller.

controller在負責。基於一些事件或者請求,controller被創建或者被存取。然後controller創建合適的view或者和model相互作用創建更深層次的view。歸結起來:controller創建和管理view;view受命於controller。view不瞭解controller。

1、簡而言之,MVP是View驅動的,View層持有一個對應Presenter的引用,View上的交互事件首先會調用Presenter提供的接口,然後Presenter調用Model提供的方法取得數據,最後Presenter將取得的數據傳遞到View上展示.

2、MVC則是由Controller驅動的,Controller持有View,並響應View上的交互事件,根據交互調用不同的Model方法取得反饋數據,再將數據傳遞給View展示.

我的理解是,MVP是用戶視角:所見即View.MVC則是程序員視角:I control everyone.

MVVM的示意圖:

這裏寫圖片描述

這裏寫圖片描述

上圖展示了MVVM與MVC的差別。

在MVC模式的iOS開發中,Controller承擔了太多的代碼,包含着我們的視圖處理邏輯和業務邏輯。

這裏寫圖片描述

在MVVM中,我們將視圖處理邏輯從C中剝離出來給V,剩下的業務邏輯部分被稱做View-Model。
使用MVVM模式的iOS應用的可測試性要好於MVC,因爲ViewModel中並不包含對View的更新,相比於MVC,減輕了Controller的負擔,使功能劃分更加合理。

而這些ViewModel的代碼並不放在ViewController中,我們的View請求自己的ViewModel來獲取所需的數據,ViewController完全歸於View。

model層,API請求的原始數據
view層,視圖展示,由viewController來控制
viewModel層,負責業務處理和數據轉化

http://www.jianshu.com/p/d56cb11ebc84

http://blog.csdn.net/hero_wqb/article/details/50890159

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章