精煉並增補於:界面之下:還原真實的MV*模式html
圖形界面的應用程序提供給用戶可視化的操做界面,這個界面提供給數據和信息。用戶輸入行爲(鍵盤,鼠標等)會執行一些應用邏輯,應用邏輯(application logic)可能會觸發必定的業務邏輯(business logic)對應用程序數據的變動,數據的變動天然須要用戶界面的同步變動以提供最準確的信息。前端
在開發應用程序的時候,以求更好的管理應用程序的複雜性,基於職責分離(Speration of Duties)的思想都會對應用程序進行分層。在開發圖形界面應用程序的時候,會把管理用戶界面的層次稱爲View,應用程序的數據爲Model(注意這裏的Model指的是Domain Model,這個應用程序對須要解決的問題的數據抽象,不包含應用的狀態,能夠簡單理解爲對象)。Model提供數據操做的接口,執行相應的業務邏輯。git
有了View和Model的分層,那麼問題就來了:View如何同步Model的變動,View和Model之間如何粘合在一塊兒?github
MV*就是實現了領域模型數據和UI層的解耦。mvc
MVC、MVP、MVVM對其解耦的思路的不一樣。從歷史的角度來看,MVC、MVP和MVVM是一種進化的關係。可是鑑於項目的規模以及模式實現的方式不一樣,不一樣的MV*模式各有其優勢和缺點,難分孰好孰壞。app
可是業界愈來愈認爲:MVVM是前端領域最好的MV*模式。Angular、Vue是MVVM模式典範框架
MVC出了把應用程序分紅View、Model層,還額外的加了一個Controller層,職責爲進行Model和View之間的協做(路由、輸入預處理等)的應用邏輯(application logic)。mvvm
Model主要是與業務數據有關。模塊化
View是應用程序數據的可視化表示。組件化
Controller管理應用程序中Model和View之間的邏輯和協調。
用戶對View的輸入等操做並不會在View的相關模塊中處理邏輯,而是由Controller層得到這些操做(所謂的Pass Call),並由Controller層對這些操做中的數據通過應用邏輯的操做,而後在調用Model層的接口,將數據交給Model層。Model層執行與業務邏輯相關的操做,並更新數據。Model和View經過觀察者模式聯繫在一塊兒,即View是Model的觀察者,當Model數據變更以後,通知View層進行數據更新。
把業務邏輯所有分離到Controller中,模塊化程度高。當業務邏輯變動的時候,不須要變動View和Model,只須要Controller換成另一個Controller就好了(Swappable Controller)。
觀察者模式能夠作到多視圖同時更新。
Controller測試困難。由於視圖同步操做是由View本身執行,而View只能在有UI的環境下運行。在沒有UI環境下對Controller進行單元測試的時候,Controller業務邏輯的正確性是沒法驗證的:Controller更新Model的時候,沒法對View的更新操做進行斷言。
View沒法組件化。View是強依賴特定的Model的,若是須要把這個View抽出來做爲一個另一個應用程序可複用的組件就困難了。由於不一樣程序的的Domain Model是不同的
MVP比起MVC模式,它的特色很明顯。MVP中M和V之間的依賴關係被消除了。
在MVC中,M和V之間經過觀察者模式依賴。這種依賴關係在MVP中被轉移到M和P層中。這樣一來P層必須經過必定的機制通知V層進行數據的更新。因此MVP模式中V層中提供了供P層調用的接口。P層做爲觀察者得到數據變化是,將調用V層的接口將變化反映到V層中。
在MVP中:
Model層依然是主要與業務數據有關。、
View依然是應用程序的可視化表示,可是在MVP中它對領域數據(Model層)徹底無知,View再也不負責同步的邏輯,而是由Presenter負責。Presenter中既有應用程序邏輯也有同步邏輯。因此比起MVC中View層更輕了。可是,View須要提供操做界面的接口給Presenter進行調用
Presenter層比較重,它不只調用Model的接口,也調用View的接口。並且須要做爲觀察者得到Model的數據更新。
便於測試。Presenter對View是經過接口進行,在對Presenter進行不依賴UI環境的單元測試的時候。能夠經過Mock一個View對象,這個對象只須要實現了View的接口便可。而後依賴注入到Presenter中,單元測試的時候就能夠完整的測試Presenter應用邏輯的正確性。這裏根據上面的例子給出了Presenter的單元測試樣例。
View能夠進行組件化。在MVP當中,View不依賴Model。這樣就可讓View從特定的業務場景中脫離出來,能夠說View能夠作到對業務徹底無知。它只須要提供一系列接口提供給上層操做。這樣就能夠作到高度可複用的View組件。
Presenter中除了應用邏輯之外,還有大量的View->Model,Model->View的手動同步邏輯,形成Presenter比較笨重,維護起來會比較困難。
Supervising Controller模式中,Presenter會把一部分簡單的同步邏輯交給View本身去作,Presenter只負責比較複雜的、高層次的UI操做,因此能夠把它當作一個Supervising Controller。
由於Supervising Controller用得比較少,MVVM能夠看做是一種特殊的MVP(Passive View)模式,或者說是對MVP模式的一種改良。
Model-View-ViewModel模式中,M層數據的變化不是經過觀察者模式通知到V層的(即沒有M和V的依賴),也不是經過VM層調用V層的接口將數據傳遞給V層的(這意味着用戶代碼不須要手動更新V層)。而是經過在VM層實現一個特殊的binder,將數據從M層直接綁定到V層。這樣ViewModel層瞭解Model層,View層瞭解ViewModel層。
ViewModel充當了一個數據轉換器的做用。它將Model信息轉換爲View信息,還將命令從View傳遞到Model。在這裏,View能夠訪問ViewModel,ViewModel能夠訪問Model。
MVVM的調用關係和MVP同樣。可是,在ViewModel當中會有一個叫Binder,或者是Data-binding engine的東西。之前所有由Presenter負責的View和Model之間數據同步操做交由給Binder處理。你只須要在View的模版語法當中,指令式地聲明View上的顯示的內容是和Model的哪一塊數據綁定的。當ViewModel對進行Model更新的時候,Binder會自動把數據更新到View上去,當用戶對View進行操做(例如表單輸入),Binder也會自動把數據更新到Model上去。這種方式稱爲:Two-way data-binding,雙向數據綁定。能夠簡單而不恰當地理解爲一個模版引擎,可是會根據數據變動實時渲染。
MVVM把View和Model的同步邏輯自動化了。之前Presenter負責的View和Model同步再也不手動地進行操做,而是交由框架所提供的Binder進行負責。只須要告訴Binder,View顯示的數據對應的是Model哪一部分便可。
雙向綁定技術,當Model變化時,View-Model會自動更新,View也會自動變化。很好作到數據的一致性,不用擔憂,在模塊的這一塊數據是這個值,在另外一塊就是另外一個值了。因此 MVVM模式有些時候又被稱做:model-view-binder模式。
提升可維護性。解決了MVP大量的手動View和Model同步的問題,提供雙向綁定機制。提升了代碼的可維護性。
簡化測試。由於同步邏輯是交由Binder作的,View跟着Model同時變動,因此只須要保證Model的正確性,View就正確。大大減小了對View同步更新的測試。
過於簡單的圖形界面不適用,或說牛刀殺雞。
對於大型的圖形應用程序,視圖狀態較多,ViewModel的構建和維護的成本都會比較高。
數據綁定的聲明是指令式地寫在View的模版當中的,這些內容是沒辦法去打斷點debug的。
一個大的模塊中model也會很大,雖然使用方便了也很容易保證了數據的一致性,當時長期持有,不釋放內存就形成了花費更多的內存。
數據雙向綁定不利於代碼重用。客戶端開發最經常使用的重用是View,可是數據雙向綁定技術,讓你在一個View都綁定了一個model,不一樣模塊的model都不一樣。那就不能簡單重用View了。
若有更新,只在原文進行:再談MV*(MVVM MVP MVC)模式的設計原理-封裝與解耦,若是不妥之處,親留言告知。