本文由CocoaChina譯者 陳溪 翻譯
作者:Soroush Khanlou
原文:MVVM is Not Very Good
我寫過很多有關於讓View Controller 更易於理解的文章,其中一種比較常見的模式就是Model-View-ViewModel(MVVM)。 我認為MVVM 是一種非常容易讓人混淆的 anti-pattern(反面模式設計)。View models是很糟糕的名字,它只是優秀架構之路上的權宜之計。我們的團體將從這種模式過度到更好的模式。
MVVM 是一個很糟糕的名字
名字很重要。理想的情況下,一個名字能夠有效地表達這個對象是什麼,它扮演了什麼樣的角色,以及如何使用它等。View model作為一個名字,沒有起到任何的作用。
以我的經驗來看,考慮到view model的抽象性,它實際上代表了兩種迥然不同的模式
第一種 “view model” 是 “model for the view”。這是一個dumb object(在Swift中絕對是一個結構體) 用來傳遞 view 給它的子視圖。它不應該包含任何邏輯甚至是任何方法。這跟UILabel包含string,或者UIImageView包含Image,自定義profileView包含profileViewModel 是一樣的道理。它直接傳遞給你的ProfileView,最重要的是,它允許你將子視圖私有化,而不是將子視圖暴露在外面。這是一個非常好的方法。我見過一種叫 view data 的模式,我非常喜歡這種模式,因為它將自己從定義模糊不清的”view model” 中剝離出來了。
View model 同時也一種介於model object和view controller之間模糊的、抽象的名詞。它處理數據展示、網絡請求獲取數據、表單驗證和你認為可以放在這裡的其他任務。這種萬金油風格的對象主要用來減輕控制器的壓力。但是最終,你只是多建立了一個能夠讓你將任務分工倒進去的容器。
MVVM 承擔了更多的責任
這種缺乏具體內涵的名字導致了這個類負責的東西無限地增長。那麼什麼樣的功能才應該放在 view model 中呢?沒人知道! 隨便寫就是了。
我們來看一些例子
Let’s discuss MVVM for iOS 這篇文章展示了view model 中的網絡數據模型 ,推薦你在裡邊添加驗證和展示邏輯。
Introduction to MVVM 這篇文章展示了如何將表示邏輯放入視圖模型中,同時引發了一個問題--為什麼它不叫 Presenter?
COCOA SAMURAI?這篇告訴你應該用view model來上傳數據並綁定ReactiveCocoa.
ReactiveCocoa and MVVM, an Introduction 這篇使用view model 來表格驗證和獲取數據。
Model-View-ViewModel for iOS 這篇文章特別建議你將“miscellaneous code”(“無法明確定義的代碼”) 放入到view model 中。
View Model非常適用於存放用戶輸入的驗證邏輯,視圖的表示邏輯, 網絡請求的初始化和其它“miscellaneous code ”的地方。
沒人知道“view model”代表著什麼,所以人們無法在view model 應該包含什麼內容這一問題上達成一致。view model 這個概念本身就太抽象了。這些作者在Validator class、Presenter class 或者 Fetcher class 該做哪些事和不該做哪些事上有不同的觀點。這些都是有著明確定義的好名字。
假設一個同樣的名字,在不同的對象中有著迥然不同的任務分工,那麼它只會混淆讀代碼的人。如果我們無法在view model 的作用上達成一致,那麼將這些不同作用的“view model”取成同一個名字又由什麼好處呢?
我們已知的規律中已經面臨了一個同樣的挑戰,並且我們發現“controller”的名字定義太廣泛了,它能夠包含很多小的任務 .
你完全可以給你自己的類定義一個你想要的名字!選一個好點的名字
MVVM並沒有改變你代碼的結構
最後,view models 本質上並沒有改變你app的結構。這兩幅圖有什麼區別?(source)
你不需要高級的圖形理論就可以看出他們基本上是完全一樣的。
我所知道這個模式最清楚的地方就是: 它將view controller 中的(view controller不是一個你擁有的對象,因為它是Apple class 的一個子類) 代碼移動到了你擁有的view model 中。這樣view controller 就很容易的能夠聚焦view生命周期時間。盡管這樣,我們的代碼還是大量的聚集在一起,它只是從view controller 移動到了 view model 中而已。
因為view model 只有一個,我們還沒有解決這個復雜的問題。如果你創建一個view model 來避免你的控制器過於臃腫,那麼如果你的app代碼又增加了一倍要怎麼辦?或許到那時候,我們可以加一個controller-model.
這種view model 解決方法不是很好,它只是在問題上貼了一個創可貼,問題還會繼續出現。我們需要一個更好的,能從根本上解決問題的辦法。就像一個能夠在對象變得更大時,你能夠對其進行持續性的劃分,好比正在進行有絲分裂的細胞。view model它只是個一次性的補丁。
其他的團體已經經歷過這樣的問題
Rails community 在幾年前就經歷過這個問題,我們能夠從他們的故事中有所借鑒。首先,他們controller非常臃腫 ,除了persistence(持久性數據)外,幾乎是一個空的模型。這樣的代碼幾乎無法測試,於是他們將所有的邏輯移動到了model中,這樣就有了簡潔的controller和臃腫的model。由於臃腫的model依靠於ActiveRecord, 這樣的話數據庫依舊很難測試並且需要拆分成很小的單元。
博客裡面已經貼出了像 7 Patterns to Refactor Fat ActiveRecord Models 這篇文章 (給了我寫8 Patterns to Help You Destroy Massive View Controller這篇文章的靈感),這是上述思維方式的產品例子。最終,你將持續將你的核心分割成小的單元,那麼移動你的代碼時就能夠有效的劃分到對應的區域。
View model作為一種解決方法,並不適用於現代編程模式的變化。他們是一種定義不清的結構,不知道應該包含什麼,這就導致了它們會遇到和view controller 一樣的問題。它們只是當我們遇到復雜問題的臨時補丁,如果我們忽略這些問題,在不久之後問題再次出現時,我們還是要解決同樣的問題。
本文僅用於學習和交流目的,轉載請注明文章譯者、作者、出處以及本文鏈接。
感謝博文視點對本期翻譯活動的支持