再談MV*(MVVM MVP MVC)模式的設計原理—封裝與解耦

精煉並增補於:界面之下:還原真實的MV*模式

圖形界面的應用程序提供給用戶可視化的操作界面,這個界面提供給數據和信息。用戶輸入行爲(鍵盤,鼠標等)會執行一些應用邏輯,應用邏輯(application logic)可能會觸發一定的業務邏輯(business logic)對應用程序數據的變更,數據的變更自然需要用戶界面的同步變更以提供最準確的信息。

在開發應用程序的時候,以求更好的管理應用程序的複雜性,基於職責分離(Speration of Duties)的思想都會對應用程序進行分層。在開發圖形界面應用程序的時候,會把管理用戶界面的層次稱爲View應用程序的數據爲Model(注意這裏的Model指的是Domain Model,這個應用程序對需要解決的問題的數據抽象,不包含應用的狀態,可以簡單理解爲對象)。Model提供數據操作的接口,執行相應的業務邏輯。

有了View和Model的分層,那麼問題就來了:View如何同步Model的變更,View和Model之間如何粘合在一起?

gui

MV*模式解決什麼問題

MV*就是實現了領域模型數據和UI層的解耦

MVC、MVP、MVVM對其解耦的思路的不同。從歷史的角度來看,MVC、MVP和MVVM是一種進化的關係。但是鑑於項目的規模以及模式實現的方式不同,不同的MV*模式各有其優點和缺點,難分孰好孰壞

但是業界越來越認爲:MVVM是前端領域最好的MV*模式。Angular、Vue是MVVM模式典範

MVC的依賴關係

MVC出了把應用程序分成View、Model層,還額外的加了一個Controller層,職責爲進行Model和View之間的協作(路由、輸入預處理等)的應用邏輯(application logic)。

  • Model主要是與業務數據有關。

  • View是應用程序數據的可視化表示。

  • Controller管理應用程序中Model和View之間的邏輯和協調。

20190430201023807304403.jpg

用戶對View的輸入等操作並不會在View的相關模塊中處理邏輯,而是由Controller層獲得這些操作(所謂的Pass Call),並由Controller層對這些操作中的數據經過應用邏輯的操作,然後在調用Model層的接口,將數據交給Model層。Model層執行與業務邏輯相關的操作,並更新數據。Model和View通過觀察者模式聯繫在一起,即View是Model的觀察者,當Model數據變動之後,通知View層進行數據更新



mvc-call

MVC優點

  • 把業務邏輯全部分離到Controller中,模塊化程度高。當業務邏輯變更的時候,不需要變更View和Model,只需要Controller換成另外一個Controller就行了(Swappable Controller)。

  • 觀察者模式可以做到多視圖同時更新。

MVC缺點

  • Controller測試困難。因爲視圖同步操作是由View自己執行,而View只能在有UI的環境下運行。在沒有UI環境下對Controller進行單元測試的時候,Controller業務邏輯的正確性是無法驗證的:Controller更新Model的時候,無法對View的更新操作進行斷言

  • View無法組件化。View是強依賴特定的Model的,如果需要把這個View抽出來作爲一個另外一個應用程序可複用的組件就困難了。因爲不同程序的的Domain Model是不一樣的

MVP模式

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的數據更新。

MVP(Passive View)的調用關係


mvp-call

MVP(Passive View)優點

  • 便於測試。Presenter對View是通過接口進行,在對Presenter進行不依賴UI環境的單元測試的時候。可以通過Mock一個View對象,這個對象只需要實現了View的接口即可。然後依賴注入到Presenter中,單元測試的時候就可以完整的測試Presenter應用邏輯的正確性。這裏根據上面的例子給出了Presenter的單元測試樣例。

  • View可以進行組件化。在MVP當中,View不依賴Model。這樣就可以讓View從特定的業務場景中脫離出來,可以說View可以做到對業務完全無知。它只需要提供一系列接口提供給上層操作。這樣就可以做到高度可複用的View組件。

MVP(Passive View)缺點

  • Presenter中除了應用邏輯以外,還有大量的View->Model,Model->View的手動同步邏輯,造成Presenter比較笨重,維護起來會比較困難。


MVP(Supervising Controller)

Supervising Controller模式中,Presenter會把一部分簡單的同步邏輯交給View自己去做,Presenter只負責比較複雜的、高層次的UI操作,所以可以把它看成一個Supervising Controller。


mvp-sc

因爲Supervising Controller用得比較少,MVVM可以看作是一種特殊的MVP(Passive View)模式,或者說是對MVP模式的一種改良。

MVVM的依賴

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-call

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哪一部分即可。

mvvm


MVVM優點

  • 雙向綁定技術,當Model變化時,View-Model會自動更新,View也會自動變化。很好做到數據的一致性,不用擔心,在模塊的這一塊數據是這個值,在另一塊就是另一個值了。所以 MVVM模式有些時候又被稱作:model-view-binder模式。

  • 提高可維護性。解決了MVP大量的手動View和Model同步的問題,提供雙向綁定機制。提高了代碼的可維護性。

  • 簡化測試。因爲同步邏輯是交由Binder做的,View跟着Model同時變更,所以只需要保證Model的正確性,View就正確。大大減少了對View同步更新的測試。

MVVM缺點

  • 過於簡單的圖形界面不適用,或說牛刀殺雞。

  • 對於大型的圖形應用程序,視圖狀態較多,ViewModel的構建和維護的成本都會比較高。

  • 數據綁定的聲明是指令式地寫在View的模版當中的,這些內容是沒辦法去打斷點debug的。

  • 一個大的模塊中model也會很大,雖然使用方便了也很容易保證了數據的一致性,當時長期持有,不釋放內存就造成了花費更多的內存。

  • 數據雙向綁定不利於代碼重用。客戶端開發最常用的重用是View,但是數據雙向綁定技術,讓你在一個View都綁定了一個model,不同模塊的model都不同。那就不能簡單重用View了。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章