MVVM 不是那么好

作者:Soroush Khanlou,原文鏈接,原文日期:2015-12-17
譯者:zltunes;校對:Channe;定稿:shanks

我寫過許多關于讓 ViewController 變得更輕量的文章,Model-View-ViewModel 是一種常用的可以實現該目的的設計模式。我覺得 MVVM 是一種反人類的設計模式,它使架構更加混亂而非清晰。View Model的命名很糟糕,它只是架構優化的權宜之計。對我們來說放棄這一模式反而更好。

MVVM 命名很糟糕

名稱是很重要的。一個理想的名稱能夠有效地傳達出對象是干什么的,扮演什么角色以及怎么使用它。View Model這一名稱則沒有發揮任何作用。

在我看來,View Model這個十分抽象的名稱實際上指的是兩個截然不同的設計模式。

View Model的第一種含義是 model for the view(視圖的模型)。這是一個愚蠢的對象(嚴格來講 Swift 中叫struct),用來傳遞給某個視圖去填充它的子視圖。它不應該包含任何邏輯或方法。類似于UILabel需要一個字符串,UIImageView 需要一張圖像,ProfileView需要一個ProfileViewModel。該對象直接傳遞給ProfileView,它允許你的子視圖是私有的而非暴露給外界,這是很有用的一點。我更喜歡把這種設計模式叫做view data,因為它把自己從view model的另一種定義的包袱中除去了。

View model另一種含義是介于模型和視圖控制器之間的一種模糊、抽象的對象。負責將數據傳遞給表示層,有時候也作為網絡和數據庫通道,或者表單驗證以及其他類似的任務。這種“萬金油”式的對象可以為你的控制器減壓,但往往最后會成為一個新的“下水道”,什么任務都往里面堆。

MVVM 引進太多職責

命名不夠具體,導致這個類的任務無休止地增長。到底哪些任務應該交給view model?沒有人知道,好像什么都能交給它。

讓我們看一些例子。

  • 這里將網絡請求放入view model,并建議你添加驗證和表示的邏輯。
  • 這里只展示了如何將表示邏輯放到view model中,并提出為什么不把它命名為Presenter的問題。
  • 這里講到用view model上傳數據并綁定到ReactiveCocoa
  • 這里view model進行驗證和獲取數據。
  • 這里明確建議你在view model中放入“其他代碼”:

view model 非常適合干這些事:驗證邏輯、用戶輸入、視圖展示邏輯、網絡請求以及其他代碼。

沒有人知道view model到底是什么意思,所以無法就“哪些功能交給 view model”達成一致。它本身概念過于抽象。這些作者對一個 Validator 類、Presenter 類或者 Fetcher 類該做什么是沒有異議的,這些名字都起得很好,能準確傳達出對應類扮演的角色。

給用途截然不同的對象起同一個名字只能給讀者造成困惑。如果我們不能就view model的功能達成一致,為什么要給他們起這個名字?

這種看法面臨著一個類似的挑戰,我們發現controller這個名稱同樣太寬泛,無法包含一系列確切的任務。

你自己的類叫什么名字完全由你決定,選個好聽的就是了!

MVVM 不改變你的架構

view model 并不能從根本上改變你的應用程序的架構。這兩張圖有什么不同(原圖)?

不需要利用先進的圖片理論你也能看出這兩張圖幾乎是一樣的。

我能想到的 MVVM 模式最大的好處就是它把“下水道”從蘋果自帶的 view controoller類轉移到了view model這一自定義的對象。view controller只需要專注于視圖生命周期事件即可,變得很簡潔。盡管如此,還是有“下水道”存在,僅僅是轉移了而已。

由于view model只是給 app 添加的一層定義簡陋的模塊,仍無法解決復雜性的問題。如果你為了避免view controller過于臃腫而創建了view model,那么當你的代碼規模加倍的時候會發生什么?也許我們可以加一個controller-model層。

view model方案不能大規模擴張。對于它想解決的問題來說只能做到緩解而無法完全避免。我們需要一個更佳的方案,比如可以嘗試隨著一個對象的增大不斷去分解它,像細胞進行有絲分裂一樣。View model只是權宜之計。

其他社區也曾面臨該問題

幾年前 Rails 社區也曾遇到這種問題,他們也想出了解決方案,我們可以從中獲得一些啟示。首先他們有臃腫的controller以及幾乎沒什么內容的model。這種情況下很難進行測試,所以把所有的邏輯代碼分解到model中,最終controller變得很簡潔,model變得臃腫。復雜的model依賴于ActiveRecord和數據庫,依舊難以測試,仍需要繼續分割成更小的部分。

7 Patterns to Refactor Fat ActiveRecord Models 這篇博客受到8 Patterns to Help You Destroy Massive View Controller的影響,是這一系列想法下的產物。總而言之你仍需要將那些惱人的東西分割成小的單元,“轉移下水道”的做法僅是緩解之計。

view model是一種完全無法應對現代編程挑戰的做法,命名糟糕,對自己包含的功能不明確,最終面臨和controller一樣的問題。它只是對復雜情形的權宜之計,如果我們不去避免這種做法,很快又會面臨同樣的問題。

本文由 SwiftGG 翻譯組翻譯,已經獲得作者翻譯授權,最新文章請訪問 http://swift.gg

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容