精煉并增補于:界面之下:還原真實的MV*模式
圖形界面的應用程序提供給用戶可視化的操作界面,這個界面提供給數據和信息。用戶輸入行為(鍵盤砍鸠,鼠標等)會執(zhí)行一些應用邏輯湃望,應用邏輯(application logic)可能會觸發(fā)一定的業(yè)務邏輯(business logic)對應用程序數據的變更,數據的變更自然需要用戶界面的同步變更以提供最準確的信息院喜。
在開發(fā)應用程序的時候亡蓉,以求更好的管理應用程序的復雜性,基于職責分離(Speration of Duties)的思想都會對應用程序進行分層喷舀。在開發(fā)圖形界面應用程序的時候砍濒,會把管理用戶界面的層次稱為View,應用程序的數據為Model(注意這里的Model指的是Domain Model硫麻,這個應用程序對需要解決的問題的數據抽象爸邢,不包含應用的狀態(tài),可以簡單理解為對象)拿愧。Model提供數據操作的接口杠河,執(zhí)行相應的業(yè)務邏輯。
有了View和Model的分層浇辜,那么問題就來了:View如何同步Model的變更券敌,View和Model之間如何粘合在一起?
MV*模式解決什么問題
MV*就是實現了領域模型數據和UI層的解耦。
MVC柳洋、MVP待诅、MVVM對其解耦的思路的不同。從歷史的角度來看熊镣,MVC卑雁、MVP和MVVM是一種進化的關系。但是鑒于項目的規(guī)模以及模式實現的方式不同绪囱,不同的MV*模式各有其優(yōu)點和缺點测蹲,難分孰好孰壞。
但是業(yè)界越來越認為:MVVM是前端領域最好的MV*模式毕箍。Angular弛房、Vue是MVVM模式典范
MVC的依賴關系
MVC出了把應用程序分成View、Model層而柑,還額外的加了一個Controller層文捶,職責為進行Model和View之間的協(xié)作(路由荷逞、輸入預處理等)的應用邏輯(application logic)。
Model主要是與業(yè)務數據有關粹排。
View是應用程序數據的可視化表示种远。
Controller管理應用程序中Model和View之間的邏輯和協(xié)調。
用戶對View的輸入等操作并不會在View的相關模塊中處理邏輯顽耳,而是由Controller層獲得這些操作(所謂的Pass Call)坠敷,并由Controller層對這些操作中的數據經過應用邏輯的操作,然后在調用Model層的接口射富,將數據交給Model層膝迎。Model層執(zhí)行與業(yè)務邏輯相關的操作,并更新數據胰耗。Model和View通過觀察者模式聯系在一起限次,即View是Model的觀察者,當Model數據變動之后柴灯,通知View層進行數據更新卖漫。
MVC優(yōu)點
把業(yè)務邏輯全部分離到Controller中,模塊化程度高赠群。當業(yè)務邏輯變更的時候羊始,不需要變更View和Model,只需要Controller換成另外一個Controller就行了(Swappable Controller)查描。
觀察者模式可以做到多視圖同時更新突委。
MVC缺點
Controller測試困難。因為視圖同步操作是由View自己執(zhí)行叹誉,而View只能在有UI的環(huán)境下運行鸯两。在沒有UI環(huán)境下對Controller進行單元測試的時候,Controller業(yè)務邏輯的正確性是無法驗證的: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層依然是主要與業(yè)務數據有關泣特。浩姥、
View依然是應用程序的可視化表示,但是在MVP中它對領域數據(Model層)完全無知状您,View不再負責同步的邏輯勒叠,而是由Presenter負責。Presenter中既有應用程序邏輯也有同步邏輯膏孟。所以比起MVC中View層更輕了眯分。但是,View需要提供操作界面的接口給Presenter進行調用
Presenter層比較重柒桑,它不僅調用Model的接口颗搂,也調用View的接口。而且需要作為觀察者獲得Model的數據更新幕垦。
MVP(Passive View)的調用關系
MVP(Passive View)優(yōu)點
便于測試丢氢。Presenter對View是通過接口進行,在對Presenter進行不依賴UI環(huán)境的單元測試的時候先改【尾欤可以通過Mock一個View對象,這個對象只需要實現了View的接口即可仇奶。然后依賴注入到Presenter中貌嫡,單元測試的時候就可以完整的測試Presenter應用邏輯的正確性。這里根據上面的例子給出了Presenter的單元測試樣例该溯。
View可以進行組件化岛抄。在MVP當中,View不依賴Model狈茉。這樣就可以讓View從特定的業(yè)務場景中脫離出來夫椭,可以說View可以做到對業(yè)務完全無知。它只需要提供一系列接口提供給上層操作氯庆。這樣就可以做到高度可復用的View組件蹭秋。
MVP(Passive View)缺點
Presenter中除了應用邏輯以外,還有大量的View->Model堤撵,Model->View的手動同步邏輯仁讨,造成Presenter比較笨重,維護起來會比較困難实昨。
MVP(Supervising Controller)
Supervising Controller模式中洞豁,Presenter會把一部分簡單的同步邏輯交給View自己去做,Presenter只負責比較復雜的、高層次的UI操作丈挟,所以可以把它看成一個Supervising Controller刁卜。
因為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的調用關系和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優(yōu)點
雙向綁定技術,當Model變化時,View-Model會自動更新想暗,View也會自動變化妇汗。很好做到數據的一致性,不用擔心说莫,在模塊的這一塊數據是這個值杨箭,在另一塊就是另一個值了。所以 MVVM模式有些時候又被稱作:model-view-binder模式储狭。
提高可維護性互婿。解決了MVP大量的手動View和Model同步的問題,提供雙向綁定機制辽狈。提高了代碼的可維護性慈参。
簡化測試。因為同步邏輯是交由Binder做的刮萌,View跟著Model同時變更驮配,所以只需要保證Model的正確性,View就正確着茸。大大減少了對View同步更新的測試壮锻。
MVVM缺點
過于簡單的圖形界面不適用,或說牛刀殺雞涮阔。
對于大型的圖形應用程序猜绣,視圖狀態(tài)較多,ViewModel的構建和維護的成本都會比較高澎语。
數據綁定的聲明是指令式地寫在View的模版當中的途事,這些內容是沒辦法去打斷點debug的。
一個大的模塊中model也會很大擅羞,雖然使用方便了也很容易保證了數據的一致性尸变,當時長期持有,不釋放內存就造成了花費更多的內存减俏。
數據雙向綁定不利于代碼重用召烂。客戶端開發(fā)最常用的重用是View娃承,但是數據雙向綁定技術奏夫,讓你在一個View都綁定了一個model,不同模塊的model都不同历筝。那就不能簡單重用View了酗昼。
如有更新,只在原文進行:再談MV*(MVVM MVP MVC)模式的設計原理-封裝與解耦梳猪,如果不妥之處麻削,親留言告知。