當前位置:
首頁 > 知識 > 淺析前端開發中的 MVC/MVP/MVVM 模式

淺析前端開發中的 MVC/MVP/MVVM 模式

MVC、MVP和MVVM都是常見的軟體架構設計模式(Architectural Pattern),它通過分離關注點來改進代碼的組織方式。不同於設計模式(Design Pattern),只是為了解決一類問題而總結出的抽象方法,一種架構模式往往使用了多種設計模式。

要了解MVC、MVP和MVVM,就要知道它們的相同點和不同點。不同部分是C(Controller)、P(Presenter)、VM(View-Model),而相同的部分則是MV(Model-View)。

Model&View

這裡有一個可以對數值進行加減操作的組件:上面顯示數值,兩個按鈕可以對數值進行加減操作,操作後的數值會更新顯示。

我們將依照這個「栗子」,嘗試用JavaScript實現簡單的具有MVC/MVP/MVVM模式的Web應用。

Model

Model層用於封裝和應用程序的業務邏輯相關的數據以及對數據的處理方法。這裡我們把需要用到的數值變數封裝在Model中,並定義了add、sub、getVal三種操作數值方法。

View

View作為視圖層,主要負責數據的展示。

現在通過Model&View完成了數據從模型層到視圖層的邏輯。但對於一個應用程序,這遠遠是不夠的,我們還需要響應用戶的操作、同步更新View和Model。

於是,在MVC中引入了控制器controller,讓它來定義用戶界面對用戶輸入的響應方式,它連接模型和視圖,用於控制應用程序的流程,處理用戶的行為和數據上的改變。

MVC

那時計算機世界天地混沌,渾然一體,然後出現了一個創世者,將現實世界抽象出模型形成model,將人機交互從應用邏輯中分離形成view,然後就有了空氣、水、雞啊、蛋什麼的。——《前端MVC變形記》

上個世紀70年代,美國施樂帕克研究中心,就是那個發明圖形用戶界面(GUI)的公司,開發了Smalltalk編程語言,並開始用它編寫圖形界面的應用程序。

到了Smalltalk-80這個版本的時候,一位叫Trygve Reenskaug的工程師為Smalltalk設計了MVC(Model-View-Controller)這種架構模式,極大地降低了GUI應用程序的管理難度,而後被大量用於構建桌面和伺服器端應用程序。

如圖,實線代表方法調用,虛線代表事件通知。

MVC允許在不改變視圖的情況下改變視圖對用戶輸入的響應方式,用戶對View的操作交給了Controller處理,在Controller中響應View的事件調用Model的介面對數據進行操作,一旦Model發生變化便通知相關視圖進行更新。

Model

Model層用來存儲業務的數據,一旦數據發生變化,模型將通知有關的視圖。

Model和View之間使用了觀察者模式,View事先在此Model上註冊,進而觀察Model,以便更新在Model上發生改變的數據。

View

view和controller之間使用了策略模式,這裡View引入了Controller的實例來實現特定的響應策略,比如這個栗子中按鈕的click事件:

如果要實現不同的響應的策略只要用不同的Controller實例替換即可。

Controller

控制器是模型和視圖之間的紐帶,MVC將響應機制封裝在controller對象中,當用戶和你的應用產生交互時,控制器中的事件觸發器就開始工作了。

這裡我們實例化View並向對應的Model實例註冊,當Model發生變化時就去通知View做更新,這裡用到了觀察者模式。

當我們執行應用的時候,使用Controller做初始化:

可以明顯感覺到,MVC模式的業務邏輯主要集中在Controller,而前端的View其實已經具備了獨立處理用戶事件的能力,當每個事件都流經Controller時,這層會變得十分臃腫。

而且MVC中View和Controller一般是一一對應的,捆綁起來表示一個組件,視圖與控制器間的過於緊密的連接讓Controller的復用性成了問題,如果想多個View共用一個Controller該怎麼辦呢?這裡有一個解決方案:

來把王者榮耀壓壓驚~其實我想說的是MVP模式……

MVP

MVP(Model-View-Presenter)是MVC模式的改良,由IBM的子公司Taligent提出。和MVC的相同之處在於:Controller/Presenter負責業務邏輯,Model管理數據,View負責顯示。

雖然在MVC里,View是可以直接訪問Model的,但MVP中的View並不能直接使用Model,而是通過為Presenter提供介面,讓Presenter去更新Model,再通過觀察者模式更新View。

與MVC相比,MVP模式通過解耦View和Model,完全分離視圖和模型使職責劃分更加清晰;由於View不依賴Model,可以將View抽離出來做成組件,它只需要提供一系列介面給上層操作。

Model

Model層依然是主要與業務相關的數據和對應處理數據的方法。

View

MVP定義了Presenter和View之間的介面,用戶對View的操作都轉移到了Presenter。比如這裡的View暴露setter介面讓Presenter調用,待Presenter通知Model更新後,Presenter調用View提供的介面更新視圖。

Presenter

Presenter作為View和Model之間的「中間人」,除了基本的業務邏輯外,還有大量代碼需要對從View到Model和從Model到View的數據進行「手動同步」,這樣Presenter顯得很重,維護起來會比較困難。

而且由於沒有數據綁定,如果Presenter對視圖渲染的需求增多,它不得不過多關注特定的視圖,一旦視圖需求發生改變,Presenter也需要改動。

運行程序時,以View為入口:

MVVM

MVVM(Model-View-ViewModel)最早由微軟提出。ViewModel指 "Model of View"——視圖的模型。這個概念曾在一段時間內被前端圈熱炒,以至於很多初學者拿jQuery和Vue做對比……

MVVM把View和Model的同步邏輯自動化了。以前Presenter負責的View和Model同步不再手動地進行操作,而是交給框架所提供的數據綁定功能進行負責,只需要告訴它View顯示的數據對應的是Model哪一部分即可。

這裡我們使用Vue來完成這個栗子。

Model

在MVVM中,我們可以把Model稱為數據層,因為它僅僅關注數據本身,不關心任何行為(格式化數據由View負責),這裡可以把它理解為一個類似json的數據對象。

View

和MVC/MVP不同的是,MVVM中的View通過使用模板語法來聲明式的將數據渲染進DOM,當ViewModel對Model進行更新的時候,會通過數據綁定更新到View。寫法如下:

ViewModel

ViewModel大致上就是MVC的Controller和MVP的Presenter了,也是整個模式的重點,業務邏輯也主要集中在這裡,其中的一大核心就是數據綁定,後面將會講到。

與MVP不同的是,沒有了View為Presenter提供的介面,之前由Presenter負責的View和Model之間的數據同步交給了ViewModel中的數據綁定進行處理,當Model發生變化,ViewModel就會自動更新;ViewModel變化,Model也會更新。

整體來看,比MVC/MVP精簡了很多,不僅僅簡化了業務與界面的依賴,還解決了數據頻繁更新(以前用jQuery操作DOM很繁瑣)的問題。因為在MVVM中,View不知道Model的存在,ViewModel和Model也察覺不到View,這種低耦合模式可以使開發過程更加容易,提高應用的可重用性。

數據綁定

雙向數據綁定,可以簡單而不恰當地理解為一個模版引擎,但是會根據數據變更實時渲染。——《界面之下:還原真實的MV*模式》

在Vue中,使用了雙向綁定技術(Two-Way-Data-Binding),就是View的變化能實時讓Model發生變化,而Model的變化也能實時更新到View。

「據說這玩意兒可以申請專利呢。」

不同的MVVM框架中,實現雙向數據綁定的技術有所不同。目前一些主流的前端框架實現數據綁定的方式大致有以下幾種:

數據劫持 (Vue)

發布-訂閱模式 (Knockout、Backbone)

臟值檢查 (Angular)

我們這裡主要講講Vue

Vue採用數據劫持&發布-訂閱模式的方式,通過ES5提供的Object.defineProperty()方法來劫持(監控)各屬性的getter、setter,並在數據(對象)發生變動時通知訂閱者,觸發相應的監聽回調。

並且,由於是在不同的數據上觸發同步,可以精確的將變更發送給綁定的視圖,而不是對所有的數據都執行一次檢測。

要實現Vue中的雙向數據綁定,大致可以劃分三個模塊:Observer、Compile、Watcher,如圖:

Observer數據監聽器

負責對數據對象的所有屬性進行監聽(數據劫持),監聽到數據發生變化後通知訂閱者。

Compiler指令解析器

掃描模板,並對指令進行解析,然後綁定指定事件。

Watcher訂閱者

關聯Observer和Compile,能夠訂閱並收到屬性變動的通知,執行指令綁定的相應操作,更新視圖。Update()是它自身的一個方法,用於執行Compile中綁定的回調,更新視圖。

數據劫持

一般對數據的劫持都是通過Object.defineProperty方法進行的,Vue中對應的函數為defineReactive,其普通對象的劫持的精簡版代碼如下:

上面完成了對數據對象的監聽,接下來還需要在監聽到變化後去通知訂閱者,這需要實現一個消息訂閱器Dep,Watcher通過Dep添加訂閱者,當數據改變便觸發Dep.notify(),Watcher調用自己的update()方法完成視圖更新。

寫著寫著發現離主題越來越遠了……數據劫持就先講這麼多吧~對於想深入vue.js的同學可以參考勾三股四的Vue.js 源碼學習筆記

總結

MV*的目的是把應用程序的數據、業務邏輯和界面這三塊解耦,分離關注點,不僅利於團隊協作和測試,更有利於維護和管理。

業務邏輯不再關心底層數據的讀寫,而這些數據又以對象的形式呈現給業務邏輯層。從MVC-->MVP-->MVVM,就像一個打怪升級的過程,它們都是在MVC的基礎上隨著時代和應用環境的發展衍變而來的。

在我們糾結於使用什麼架構模式或框架的時候,不如先了解它們。靜下來思考業務場景和開發需求,不同需求下會有最適合的解決方案。

我們使用這個框架就代表認同它的思想,相信它能夠提升開發效率解決當前的問題,而不僅僅是因為大家都在學。

有人對新技術樂此不疲,有人對新技術不屑一顧。正如狄更斯在《雙城記》中寫的:

這是最好的時代,這是最壞的時代,這是智慧的時代,這是愚蠢的時代;這是信仰的時期,這是懷疑的時期;這是光明的季節,這是黑暗的季節;這是希望之春,這是失望之冬;人們面前應有盡有,人們面前一無所有;人們正在直登天堂;人們正在直下地獄。

請保持一顆擁抱變化的心,在新技術面前不盲目,不守舊。

寫了兩天,也查閱了很多資料,對於我而言也是一次學習的過程。希望對看完本文後的同學有所幫助。不足之處請多指教。

文章來源:

http://www.tuicool.com/articles/Nnyi2eM

點擊展開全文

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 優才學院 的精彩文章:

JavaScript初學者必看「箭頭函數」
學會插畫的這四種玩法,能讓你的UI體驗更優異
BootStrap基礎
再談PHP錯誤與異常處理

TAG:優才學院 |

您可能感興趣

The Void與ILMxLAB宣布將開發5款全新VR體驗
XRDC 2018年AR/VR報告發現HTC Vive最受VR開發者歡迎
HTC邀請第三方開發者為Vive Pro研發AR SDK
AMD加持,用Mac做VR開發,蘋果MacOS開始支持eGPU
HTC Vive Pro VR頭顯已經向開發者發貨
HTC Vive Pro VR 頭顯已向開發者交付
GDC:VR遊戲開發熱情下滑 Vive仍最受VR開發者喜愛
前端開發(HTML+CSS靜態部分)
ASP.NET Core MVC+EF Core從開發到部署
英偉達推出VR開發者中間件VRWorks SDK 3.0
VR看房APP開發
INNOVATIVE BIORESEARCH推出令牌銷售,用以開發新的艾滋病治療研究與去中心化臨床數據
MRTK是一款面向WMR、HoloLens開發的MR開源工具
隨遇而安的DAPP開發實踐教程(二)使用HTML作為DAPP前端
VR+智能家居APP開發
IBM和Unity聯手 VR/AR遊戲開發新增AI功能
GDC開發者調查:AR/VR熱情褪去 Switch成為寵兒
快訊:機動戰士GUNDAM MOBILE SUIT ENSEMBLE 開發中新品爆照
DISCO和VISYON合作開發新的教育AR應用程序
用於PHP開發的VS代碼