淺談MVC/MVP/MVVM模式(概述)

夜曉宸發表於2019-02-28

本文來自我的部落格這個想法不一定對系列,so,這個想法不一定對?

一切皆為資料(0,1),一切皆可量化

不管承不承認,頁面的展示都是資料的視覺化。HTML 是資料,CSS 是資料,JS也是資料。只是這些資料的組合最終變成了我們想要的效果。

最為直觀的是,我們在開發者工具 Console 控制檯中,輸入任何形式的資料並點選 Enter 時,最終會在下方顯示出來(前提是輸入正確的資料型別和格式)。又或者,我們用某些引數從服務請求一個 JSON 檔案,瀏覽器上就會展示檔案內容。資料 => 檢視,就是這麼簡單直接。

引子

然而,實際上的情況遠遠比這複雜。為了更好的視覺享受和使用者體驗,瀏覽器上的頁面效果越來越炫,互動邏輯也越來越複雜。我們拿到的第一手資料(或來自使用者,或來自服務)已經不能直接用來展示了,而是要經過相應的邏輯處理(在這裡我們稱第一手資料為源資料,經過邏輯處理後的資料稱為目標資料)。檢視上的資料就是目標資料的對映。

而處理後的資料又該如何展示呢?是基於 DOM 做操作,還是基於目標資料重新渲染呢?兩者都可,前者是以 jQuery 為代表,後者則是以 Vue 等新框架為主。舉個例子?,對於某個 DOM 元素的顯隱。

< !--jQuery -->
  <div id='jquery'></div>
$('#jquery').hide();

< !--Vue -->
  <div id='jquery' v-show={id[jquery]}></div>
data: {
  id: {
    jquery: fasle
  }
}
複製程式碼

基於 DOM 操作, 如果我們需要對這個 DOM 隨時改變顯隱,就需要不斷操作 DOM 來更改樣式。 如果基於資料操作,我們只需要更改 jQuery 的值即可。

我們再回到剛才的話題,對於複雜的互動頁面,資料 => 檢視 的關係已經不再像之前那麼純淨了。為了應付複雜的場景,資料檢視 不再是狹義上的資料和檢視。資料包括了資料和資料相關的操作,檢視包括了檢視和對檢視相關的一些操作。

MV*模式

借用MV* 框架模式,這裡的 資料檢視 對應著 ModelView. 簡單點的頁面,Model - View 完全能夠應付過來。但是複雜的場景,ModelView 會分擔太多的邏輯而顯得臃腫,甚至可能包含了不在自己職責範圍內的邏輯。

此時我們就要藉助第三者來協調 ModelView 之間的關係。如何合作,其實也早有了相應的解決方案。比如 MVC、MVP、MVVM。因為重點始終在於協調 ModelView,所以它們統稱為 MV*

MVC&MVP.jpg

MVC (Model(模型)-View(檢視)-Controller(控制器)), MVP (Model(模型)-View(檢視)-Presenter(中介者)) 以及 MVVM (Model(模型)-View(檢視)-ViewModel(檢視模型)),是種模式也是種抽象的概念。

每一種模式在實踐中可能存在著不同的變體,但這不妨礙它們屬於同一個模式。每一種模式的不同變體都是為了解決不同問題而產生的,所以它們沒有什麼優劣之分。

現在我們就把三種模式擬人化來闡述不同模式的運作方式。

由四節電池驅動的J-20模型:

J-20.jpg

MVC

公司:飛機模型製造商 => 生產的飛機模型可以自主塑形。

模式:MVC

飛機模型 V:由模型資料生產出的模型。職責有:由模型資料自主塑形、將收集使用者反饋並轉發。

工程師 M:負責將客服的需求引數轉換成最終的模型資料。職責有:對資料的操作、通知飛機模型更新。

工程師 C:協調 M 和 V。負責響應使用者、呼叫工程師M生成目標資料。

首先我們要知道,客戶提出了想要一個 60cm * 60cm 的飛機模型,這個需求到了製造商那裡肯定不是給出個 60cm * 60cm 的小方塊,而是根據需求計算處理生產真正的飛機模型(比如什麼樣的造型設計才能最大減少阻力),工程師M的工作之一就是根據原始資料並結合特定的邏輯規則給出最終的模型資料。

現在,使用者手裡有一飛機模型V,不過這個飛機模型的飛機雙翼和使用者想象的不一樣。於是使用者根據飛機模型上提供的方式反饋了問題(比如飛機模型提供了留言功能,用來收集使用者反饋)。工程師C收到了反饋後,把工程師M拉過來對資料進行處理並生成新的模型資料,並讓工程師M通知到共享相同資料的飛機模型去更新資料自主調整。

插一句,說到調整,我們有兩種方式。一個是,我們可以針對使用者不滿意的地方(飛機雙翼)進行調整。一個是,我們飛機模型格式化按照最新的資料模型重新初始化一下。前者可以認為就是基於 DOM 操作的方式,後者就是基於資料的處理方式。

在 MVC 中,Model 和 View 之間耦合,檢視的更新需要 Model 去直接通知。Model 內因為有 View 的引用才能讓檢視更新。

MVC.png

MVP

如果 Model 只想做資料相關的操作,把通知 View 的邏輯挪到了 Control 裡,這時 Control 搖身一變稱為了 Presenter。因為解耦了 Model 和 View,也使得它們的職責劃分更加清晰。

公司:飛機模型製造商 => 生產的飛機模型可以自主塑形。

模式:MVP

飛機模型 V:由模型資料生產出的模型。職責有:由模型資料自主塑形、將收集使用者反饋並轉發。

工程師 M:負責將客服的需求引數轉換成最終的模型資料。職責有:對資料的操作。

工程師 P:協調 M 和 V。負責響應使用者、呼叫工程師M生成目標資料、更新檢視。

在 MVP 模式中,工程師M的工作專注於資料,通知的活甩給了工程師P。 和 MVC 同樣的場景,工程師P接到反饋後,把工程師M拉過來處理了資料,然後又讓飛機模型依據已經處理後的資料自主調整。每次資料的變化都要主動去通知檢視更新。

MVP.png

MVVM

如果資料變化能夠自主觸發檢視更新,對 Presenter 來說也會輕鬆不少。於是 Presenter 再次搖身一變 稱為了 ViewModel。

公司:飛機模型製造商 => 生產的飛機模型可以自主塑形。

模式:MVVM

飛機模型 V:由模型資料生產出的模型。職責有:由模型資料自主塑形、將收集使用者反饋並轉發。

工程師 M:負責將客服的需求引數轉換成最終的模型資料。職責有:對資料的操作。

工程師 VM:協調 M 和 V。負責響應使用者、呼叫工程師M生成目標資料並更新檢視。

MVVM.png

在 MVVM 中,View 和 Model 的變化似乎不大。為了在資料變化後能夠自動更新檢視,ViewModel 進行了所謂的資料繫結。ViewModel 將 目標資料 和檢視進行了繫結,在最終生成目標資料時,會觸發檢視的更新。

在這裡我們可以想象有兩份資料,一份是源資料,一份是目標資料。繫結檢視的是目標資料,這樣,我們直接修改目標資料時會觸發檢視更新。如果是源資料經處理後賦給目標資料,目標資料也會改變,也會觸發試圖更新。

總之,在 MVVM 中,檢視是目標資料的視覺化,通過改變檢視裡的資料也就等於改變了目標資料。

和 MVC、MVP 同樣的場景,不過科技發達了,工程師VM有個自動化處理程式。使用者反饋了問題,工程師VM的這個自動處理程式接到反饋自動處理並將結果發給飛機模型讓其自主調整。

以下是Vue的MVVM示意圖:

mvvmVue.png
MVC、MVP和MVVM大致就是如此,根據三種模式以及不同場景,最終演變出了不同的變體。

但是,不同的變體是針對不同問題的解決方案,指不定後來還會有 MVA、MVB..., 誰知道呢

相關文章