1. 程式人生 > >MVC和MVVM的區別和聯絡

MVC和MVVM的區別和聯絡

本文轉自 cocoaChina   http://www.cocoachina.com/ios/20150526/11930.html

MVC

任何一個正經開發過一陣子軟體的人都熟悉MVC,它意思是Model View Controller, 是一個在複雜應用設計中組織程式碼的公認模式. 它也被證實在 iOS 開發中有著第二種含義: Massive View Controller(重量級檢視控制器)。它讓許多程式設計師絞盡腦汁如何去使程式碼被解耦和組織地讓人滿意. 總的來說, iOS 開發者已經得出結論: 他們需要給檢視控制器瘦身, 並進一步分離事物;但該怎麼做呢?

MVVM

於是MVVM流行起來, 它代表Model View View-Model, 它在這幫助我們建立更易處理, 更佳設計的程式碼.

在有些情況違背蘋果建議的編碼方式不是很能講得通。我不是說不贊成這樣子, 我指的是可能會弊大於利。比如我不建議你去實現個自己的 view controller 基類並試著自己處理檢視生命週期.

帶著這種情緒, 我想提個問題: 使用除蘋果推薦的 MVC 之外的應用設計模式是愚蠢的麼?

不,有兩個原因。

  1. 蘋果沒有為解決重量級試圖控制器問題提供真正的指導. 他們留給我們來解決如何向程式碼新增更多清晰的思路. 用 MVVM 來實現這個目的想必是極好噠. (在今年 WWDC 的一些視訊中, 蘋果工程師在螢幕上的示例程式碼的確少許出現了 view-model, 不知道是否因為有它才成為了示例程式碼)

  2. MVVM, 至少是我將要在這裡展示的 MVVM 的風格, 都跟 MVC 十分相容. 彷彿我們將 MVC 進行到下一個邏輯步驟.

我不會提及 MVC/MVVM 的歷史, 因為其他地方已經有所介紹, 並且我也不精通. 我將會關注如何用它進行 iOS/Mac 開發.

定義 MVVM

  1. Model - model 在 MVVM 中沒有真正的變化. 取決於你的偏好, 你的 model 可能會或可能不會封裝一些額外的業務邏輯工作. 我更傾向於把它當做一個容納表現資料-模型物件資訊的結構體, 並在一個單獨的管理類中維護的建立/管理模型的統一邏輯。

  2. View - view 

    包含實際 UI 本身(不論是 UIView 程式碼, storyboard 和 xib), 任何檢視特定的邏輯, 和對使用者輸入的反饋. 在 iOS 中這不僅需要 UIView 程式碼和那些檔案, 還包括很多需由 UIViewController 處理的工作。

  3. View-Model 這個術語本身會帶來困惑, 因為它混搭了兩個我們已知的術語, 但卻是完全不同的東東. 它不是傳統資料-模型結構中模型的意思(又來了, 只是我喜歡這個例子). 它的職責之一就是作為一個表現檢視顯示自身所需資料的靜態模型;但它也有收集, 解釋和轉換那些資料的責任. 這留給了 view (controller) 一個更加清晰明確的任務: 呈現由 view-model 提供的資料。

關於 view-model 的更多內容

view-model 一詞的確不能充分表達我們的意圖. 一個更好的術語可能是 “View Coordinator”(感謝Dave Lee提的這個 “View Coordinator” 術語, 真是個好點子)。你可以認為它就像是電視新聞主播背後的研究人員和作家團隊。它從必要的資源(資料庫, 網路服務呼叫, 等)中獲取原始資料, 運用邏輯, 並處理成 view (controller) 的展示資料. 它(通常通過屬性)暴露給檢視控制器需要知道的僅關於顯示檢視工作的資訊(理想地你不會暴漏你的 data-model 物件)。 它還負責對上游資料的修改(比如更新模型/資料庫, API POST 呼叫)。

MVC 世界中的 MVVM

我認為 MVVM 這個首字母縮寫如同 view-model 術語一樣, 對如何使用它們進行 iOS 開發體現得有點不太準確. 讓我們再檢查下這個首字母縮寫, 瞭解下它是怎麼與 MVC 融為一體的。

為了圖解表示, 我們顛倒了 MVC 中的 V 和 C, 於是首字母縮寫更能準確地反映出元件間的關係方位, 給我們帶來 MCV. 我也會對 MVVM 這麼幹, 將 V(iew) 移到 VM 的右邊最終成為了 MVMV. (我相信這些首字母縮寫起初不排成這樣更合理的順序是有原因的。)

這是這兩種模式如何在 iOS 中組裝在一起的簡單對映:

70.png

  • 我試圖遵循區塊尺寸(非常)大致對應它們負責的工作量。

  • 你可以看到我們巨大的檢視控制器和 view-model 之間有大塊工作上的重合。

  • 你也可以看看檢視控制器在 MVVM 中的足跡有多大一部分是跟檢視重合的。

你大可安心獲知我們並沒有真的去除檢視控制器的概念或拋棄 “controller” 術語來匹配 MVVM。 (唷. )我們正要將重合的那塊工作剝離到 view-model 中, 並讓檢視控制器的生活更加簡單。

我們實際上最終以 MVMCV 告終. Model View-Model Controller View. 我確信我無拘無束的應用設計模式駭客行為會讓人大吃一驚。

MCVMVMV.gif

我們的結果:

QQ截圖20150525162521.png

現在檢視控制器僅關注於用 view-model 的資料配置和管理各種各樣的檢視, 並在先關使用者輸入時讓 view-model 獲知並需要向上遊修改資料. 檢視控制器不需要了解關於網路服務呼叫, Core Data, 模型物件等. (事實上有時通過 view-model 標頭檔案而不是複製一大堆屬性來暴漏 model 是很務實的, 後面還會有)

view-model 會在檢視控制器上以一個屬性的方式存在. 檢視控制器知道 view-model 和它的公有屬性, 但是 view-model 對檢視控制器一無所知. 你早就該對這個設計感覺好多了因為我們的關注點在這兒進行更好地分離.

幫助你理解我們如何把元件組裝在一起還有元件對應職責的另一種方式, 就是著眼於我們新的應用構建模組層級圖.

QQ截圖20150525162551.png

View-Model 和 View Controller, 在一起,但獨立

我們來看個簡單的 view-model 標頭檔案來對我們新構件的長相有個更好地概念. 為了情節簡單, 我們構建按了一個偽造的推特客戶端來檢視任何推特使用者的最新回覆, 通過輸入他們的姓名並點選 “Go”. 我們的樣例介面將會是這樣:

  • 有一個讓使用者輸入他們姓名的 UITextField , 和一個寫著 “Go” 的 UIButton

  • 有顯示被檢視的當前使用者頭像和姓名的 UIImageView 和 UILabel 各一個

  • 下面放著一個顯示最新回覆推文的 UITableView

  • 允許無限滾動

88.png

View-Model 例項

我們的 view-model 標頭檔案應該長這樣:

1 2 3 4 5 6 7 8 9 10 11 12 13 //MYTwitterLookupViewModel.h @interface MYTwitterLookupViewModel: NSObject @property (nonatomic, assign, readonly, getter=isUsernameValid) BOOL usernameValid; @property (nonatomic, strong, readonly) NSString *userFullName; @property (nonatomic, strong, readonly) UIImage *userAvatarImage; @property (nonatomic, strong, readonly) NSArray *tweets; @property (nonatomic, assign, readonly) BOOL allTweetsLoaded; @property (nonatomic, strong, readwrite) NSString *username; - (void) getTweetsForCurrentUsername; - (void) loadMoreTweets;

相當直截了當的填充. 注意到這些壯麗的 readonly 屬性了麼?這個 view-model 暴漏了檢視控制器所必需的最小量資訊, 檢視控制器實際上並不在乎 view-model 是如何獲得這些資訊的. 現在我們兩者都不在乎. 僅僅假定你習慣於標準的網路服務請求, 校驗, 資料操作和儲存.

view-model 不做的事兒

  • 對檢視控制器以任何形式直接起作用或直接通告其變化

View Controller(檢視控制器)

檢視控制器從 view-model 獲取的資料將用來:

  • 當 usernameValid 的值發生變化時觸發 “Go” 按鈕的 enabled 屬性

  • 當 usernameValid 等於 NO 時調整按鈕的 alpha 值為0. 5(等於 YES 時設為1. 0)

  • 更新 UILable 的 text 屬性為字串 userFullName 的值

  • 更新 UIImageView 的 image 屬性為 userAvatarImage 的值

  • 用 tweets 陣列中的物件設定表格檢視中的 cell (後面會提到)

  • 當滑到表格檢視底部時如果 allTweetsLoaded 為 NO, 提供一個 顯示 “loading” 的 cell

檢視控制器將對 view-model 起如下作用:

  • 每當 UITextField 中的文字發生變化, 更新 view-model 上僅有的 readwrite 屬性 username

  • 當 “Go” 按鈕被按下時呼叫 view-model 上的 getTweetsForCurrentUsername 方法

  • 當到達表格中的 “loading” cell 時呼叫 view-model 上的 loadMoreTweets 方法

檢視控制器不做的事兒:

  • 發起網路服務呼叫

  • 管理 tweets 陣列

  • 判定 username 內容是否有效

  • 將使用者的姓和名格式化為全名

  • 下載使用者頭像並轉成 UIImage(如果你習慣在 UIImageView 上使用類別從網路載入圖片, 你可以暴漏 URL 而不是圖片. 這樣沒有讓 view-model 和 UIKit 更完全擺脫, 但我視 UIImage 為資料而非資料的確切顯示. 這些東西不是固定死的. )

  • 流汗

請再次注意檢視控制器總的責任是處理 view-model 中的變化.

子 View-Model

我提到過使用 view-model 上的 tweets 陣列中的物件配置表格檢視的 cell. 通常你會期待展現 tweets 的是資料-模型物件. 你可能已經對其感到奇怪, 因為我們試圖通過 MVVM 模式不暴漏資料-模型物件. (前面提到過的)

view-model 不必在螢幕上顯示所有東西. 你可用子 view-model 來代表螢幕上更小, 更潛在被封裝的部分. 如果一個檢視上的一小塊兒(比如表格的 cell)在 app 中可以被重用以及(或)表現多個數據-模型物件, 子 view-model 會格外有利.

你不總是需要子 view-model. 比如, 我可能用表格 header 檢視來渲染我們“tweetboat plus”應用的頂部. 它不是個可重用的元件, 所以我可能僅是將我們已經給檢視控制器用過的相同的 view-model 傳給那個自定義的 header 檢視. 它會用到 view-model 中它需要的資訊, 而無視餘下的部分. 這對於保持子檢視同步是極好的方式, 因為它們可以有效地與資訊中相同確切的上下文作用, 並觀察確切相同屬性的更新.

在我們的例子中, tweets 陣列將會被下面這樣的子 view-model 充滿:

1 2 3 4 5 6 //MyTweetCellViewModel.h @interface MYTweetCellViewModel: NSObject @property (nonatomic, strong, readonly) NSString *tweetAuthorFullName; @property (nonatomic, strong, readonly) UIImage *tweetAuthorAvatarImage;

相關推薦

KEIL、uVisionMDK區別聯絡

--------------------------------------------- -- 時間:2018-11-26 -- 建立人:Ruo_Xiao -- 郵箱:[email protected] ----------------------------------------

Java 的equals()方法 == 的區別聯絡

淺談Java中的equals和==  在初學Java時,可能會經常碰到下面的程式碼: String str1 = new String("hello"); String str2 = new String("hello"); System.out.print

關於unionjoin區別聯絡

union和join是需要聯合多張表時常見的關聯詞,具體概念我就不說了,想知道上網查就行,因為我也記不準確。 先說差別:union對兩張表的操作是合併資料條數,等於是縱向的,要求是兩張表字段必須是相同的(Schema of both sidesof union should match.)。也就

Python pip pip3區別 聯絡

python 有python2和python3的區別 那麼pip也有pip和pip3的區別 大概是這樣的 pip是python的包管理工具,pip和pip3版本不同,都位於Scripts\目錄下: 如果

後端---Java中ArrayListLinkedList區別聯絡

ArrayList和LinkedList的區別和聯絡 在一個多月之前,我曾寫過一篇部落格想要迅速簡潔的瞭解Java中所有的集合型別(List、Set、Map),然後一個月多後的我不得已又抱起《Java核心卷I 》仔細研讀,這是為什麼呢??? 是因為“溫故而知新”還是因為“書讀百遍其

C#中結構體區別聯絡

結構體 結構體定義 結構體是一種值型別,通常用來封裝小型相關變數組。例如座標或者商品的特徵。 結構體是一種自定義的資料型別,相當於一個複合容器,可以儲存多種型別。 結構體由結構體成員構成,結構體成員包含欄位,屬性與方法 結構體建

Bagging演算法Boosting區別聯絡

參考文章連結:http://www.cnblogs.com/liuwu265/p/4690486.html Bagging和Boosting都是將弱分類器組裝成強分類器的方法 備註:弱分類器也是有一定限制的起碼分類效果要比隨機分類效果好,即準確率要大於50%, 否則即使

android MVC && MVP && MVVM分析對比

  面試的時候被問到這個問題,用過,也瞭解過,但是還是不夠深入,總結一下。   MVC,MVP和MVVM是軟體比較常用的三種軟體架構,這三種架構的目的都是分離關注,避免將過多的邏輯全部堆積在一個類中,以android為例,在activity中既有UI的相關處理

PCASVD區別聯絡

前言: PCA(principal component analysis)和SVD(Singular value decomposition)是兩種常用的降維方法,在機器學習等領域有廣泛的應用。本文主要介紹這兩種方法之間的區別和聯絡。 一、PCA

Filter、ServletListener區別聯絡

1. Servlet 可以用來建立並返回一個包含基於客戶請求性質的動態內容的完整的html頁面;可以建立可嵌入到現有的html頁面中的一部分html頁面(html片段);可以讀取客戶端發來的隱藏資料;可以 讀取客戶端發來的顯示資料;可以與其他伺服器資源(包括資料庫和jav

知識點 - python 裝飾器@staticmethod@classmethod區別使用

定義 整潔 參數 sel spa elf pri Go assm 1.通常來說,我們使用一個類的方法時,首先要實例化這個類,再用實例化的類來調用其方法 class Test(object): """docstring for Test""" def

hashCode() equals() 區別作用(轉)

person set集合 static out fin 解決 詳細 返回 art 出處:https://www.jianshu.com/p/5a7f5f786b75 本章的內容主要解決下面幾個問題: 1 equals() 的作用是什麽? 2 equal

Java之JSONObject存取值以及HashMap區別, optString()getString()區別他的遍歷方式

結論: 1.JSONObject和HashMap用法上是一樣的,用put()方法存對於的Key-values鍵值對,取可用optString(key)和getString(key),get(key),存入的是什麼型別,取出來的時候就是什麼型別 2**.optString()在沒找到k

spring classpath:classpath*:區別實際應用

classpath:和classpath*:的含義 classpath: :表示從類路徑中載入資源,classpath:和classpath:/是等價的,都是相對於類的根路徑。資原始檔庫標準的在檔案系統中,也可以在JAR或ZIP的類包中。 classpath*::假設多個JAR包或檔

MybatisHibernate區別應用場景

hibernate: 是一個標準的ORM框架(物件關係對映)。入門門檻較高,不需要程式寫sql語句,sql語句自動生產了。 特點: 對sql的優化比較困難。 Hibernate對物件的維護和快取要比MyBatis好,對增刪改查的物件的維護要方便。 Hibernate資料庫移植性很好,MyB

ServiceIntentService 區別使用

背景 最近開發遇到一個小小的問題,因為沒怎麼用過IntentService ,所以對其生命週期也不很瞭解,還有工作原理。 intentService 詳解 intentService ——>> StartService 第一次 intent

G++C++區別評測注意事項

G++和C++的區別和評測注意事項 下面摘抄自網際網路 G++ 首先更正一個概念,C++是一門計算機程式語言,G++不是語言,是一款編譯器中編譯C++程式的命令而已。 那麼他們之間的區別是什麼? 在提交題目中的語言選項裡,G++和C++都代表編譯的方式。準確地說

BTCBCH 區別聯系?

升級問題 fff 手續費 升級 現在 風險 個人電腦 電網 pan 在比特幣剛剛出現的時期,中本聰對區塊的大小限制在1M。這種限制既保障性能較弱的個人電腦能夠參與其中,同時也起到了防止攻擊者讓比特幣網絡超載的風險發生,畢竟那時系統還很脆弱。在1M的限制下,10分鐘一個區塊最

SparkSQL(8):DataSetDataFrame區別轉換

1.概念: (1)DataSet和RDD   大資料的框架許多都要把記憶體中的資料往磁盤裡寫,所以DataSet取代rdd和dataframe。因為,現階段底層序列化機制使用的是java的或者Kryo的形式。但是,java序列化出來的資料很大,影響儲存Kryo對於小資料量

網路---HttpsHttp區別對稱加密非對稱加密

Https和Http區別 眾所周知,WEB服務存在http和https兩種通訊方式,http預設採用80作為通訊埠,對於傳輸採用不加密的方式,https預設採用443,對於傳輸的資料進行加密傳輸 目前主流的網站基本上開始預設採用HTTPS作為通訊方式,一切的考慮都基於對安全的要求,那麼如何對