1. 程式人生 > >再談MV*(MVVM MVP MVC)模式的設計原理—封裝與解耦

再談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了。