您好,登錄后才能下訂單哦!
精煉并增補(bǔ)于:界面之下:還原真實(shí)的MV*模式
圖形界面的應(yīng)用程序提供給用戶可視化的操作界面,這個(gè)界面提供給數(shù)據(jù)和信息。用戶輸入行為(鍵盤,鼠標(biāo)等)會(huì)執(zhí)行一些應(yīng)用邏輯,應(yīng)用邏輯(application logic)可能會(huì)觸發(fā)一定的業(yè)務(wù)邏輯(business logic)對(duì)應(yīng)用程序數(shù)據(jù)的變更,數(shù)據(jù)的變更自然需要用戶界面的同步變更以提供最準(zhǔn)確的信息。
在開發(fā)應(yīng)用程序的時(shí)候,以求更好的管理應(yīng)用程序的復(fù)雜性,基于職責(zé)分離(Speration of Duties)的思想都會(huì)對(duì)應(yīng)用程序進(jìn)行分層。在開發(fā)圖形界面應(yīng)用程序的時(shí)候,會(huì)把管理用戶界面的層次稱為View,應(yīng)用程序的數(shù)據(jù)為Model(注意這里的Model指的是Domain Model,這個(gè)應(yīng)用程序?qū)π枰鉀Q的問題的數(shù)據(jù)抽象,不包含應(yīng)用的狀態(tài),可以簡(jiǎn)單理解為對(duì)象)。Model提供數(shù)據(jù)操作的接口,執(zhí)行相應(yīng)的業(yè)務(wù)邏輯。
有了View和Model的分層,那么問題就來(lái)了:View如何同步Model的變更,View和Model之間如何粘合在一起?
MV*就是實(shí)現(xiàn)了領(lǐng)域模型數(shù)據(jù)和UI層的解耦。
MVC、MVP、MVVM對(duì)其解耦的思路的不同。從歷史的角度來(lái)看,MVC、MVP和MVVM是一種進(jìn)化的關(guān)系。但是鑒于項(xiàng)目的規(guī)模以及模式實(shí)現(xiàn)的方式不同,不同的MV*模式各有其優(yōu)點(diǎn)和缺點(diǎn),難分孰好孰壞。
但是業(yè)界越來(lái)越認(rèn)為:MVVM是前端領(lǐng)域最好的MV*模式。Angular、Vue是MVVM模式典范
MVC出了把應(yīng)用程序分成View、Model層,還額外的加了一個(gè)Controller層,職責(zé)為進(jìn)行Model和View之間的協(xié)作(路由、輸入預(yù)處理等)的應(yīng)用邏輯(application logic)。
Model主要是與業(yè)務(wù)數(shù)據(jù)有關(guān)。
View是應(yīng)用程序數(shù)據(jù)的可視化表示。
Controller管理應(yīng)用程序中Model和View之間的邏輯和協(xié)調(diào)。
用戶對(duì)View的輸入等操作并不會(huì)在View的相關(guān)模塊中處理邏輯,而是由Controller層獲得這些操作(所謂的Pass Call),并由Controller層對(duì)這些操作中的數(shù)據(jù)經(jīng)過應(yīng)用邏輯的操作,然后在調(diào)用Model層的接口,將數(shù)據(jù)交給Model層。Model層執(zhí)行與業(yè)務(wù)邏輯相關(guān)的操作,并更新數(shù)據(jù)。Model和View通過觀察者模式聯(lián)系在一起,即View是Model的觀察者,當(dāng)Model數(shù)據(jù)變動(dòng)之后,通知View層進(jìn)行數(shù)據(jù)更新。
把業(yè)務(wù)邏輯全部分離到Controller中,模塊化程度高。當(dāng)業(yè)務(wù)邏輯變更的時(shí)候,不需要變更View和Model,只需要Controller換成另外一個(gè)Controller就行了(Swappable Controller)。
觀察者模式可以做到多視圖同時(shí)更新。
Controller測(cè)試?yán)щy。因?yàn)?span >視圖同步操作是由View自己執(zhí)行,而View只能在有UI的環(huán)境下運(yùn)行。在沒有UI環(huán)境下對(duì)Controller進(jìn)行單元測(cè)試的時(shí)候,Controller業(yè)務(wù)邏輯的正確性是無(wú)法驗(yàn)證的:Controller更新Model的時(shí)候,無(wú)法對(duì)View的更新操作進(jìn)行斷言。
View無(wú)法組件化。View是強(qiáng)依賴特定的Model的,如果需要把這個(gè)View抽出來(lái)作為一個(gè)另外一個(gè)應(yīng)用程序可復(fù)用的組件就困難了。因?yàn)椴煌绦虻牡腄omain Model是不一樣的
MVP比起MVC模式,它的特點(diǎn)很明顯。MVP中M和V之間的依賴關(guān)系被消除了。
在MVC中,M和V之間通過觀察者模式依賴。這種依賴關(guān)系在MVP中被轉(zhuǎn)移到M和P層中。這樣一來(lái)P層必須通過一定的機(jī)制通知V層進(jìn)行數(shù)據(jù)的更新。所以MVP模式中V層中提供了供P層調(diào)用的接口。P層作為觀察者獲得數(shù)據(jù)變化是,將調(diào)用V層的接口將變化反映到V層中。
在MVP中:
Model層依然是主要與業(yè)務(wù)數(shù)據(jù)有關(guān)。、
View依然是應(yīng)用程序的可視化表示,但是在MVP中它對(duì)領(lǐng)域數(shù)據(jù)(Model層)完全無(wú)知,View不再負(fù)責(zé)同步的邏輯,而是由Presenter負(fù)責(zé)。Presenter中既有應(yīng)用程序邏輯也有同步邏輯。所以比起MVC中View層更輕了。但是,View需要提供操作界面的接口給Presenter進(jìn)行調(diào)用
Presenter層比較重,它不僅調(diào)用Model的接口,也調(diào)用View的接口。而且需要作為觀察者獲得Model的數(shù)據(jù)更新。
便于測(cè)試。Presenter對(duì)View是通過接口進(jìn)行,在對(duì)Presenter進(jìn)行不依賴UI環(huán)境的單元測(cè)試的時(shí)候??梢酝ㄟ^Mock一個(gè)View對(duì)象,這個(gè)對(duì)象只需要實(shí)現(xiàn)了View的接口即可。然后依賴注入到Presenter中,單元測(cè)試的時(shí)候就可以完整的測(cè)試Presenter應(yīng)用邏輯的正確性。這里根據(jù)上面的例子給出了Presenter的單元測(cè)試樣例。
View可以進(jìn)行組件化。在MVP當(dāng)中,View不依賴Model。這樣就可以讓View從特定的業(yè)務(wù)場(chǎng)景中脫離出來(lái),可以說(shuō)View可以做到對(duì)業(yè)務(wù)完全無(wú)知。它只需要提供一系列接口提供給上層操作。這樣就可以做到高度可復(fù)用的View組件。
Presenter中除了應(yīng)用邏輯以外,還有大量的View->Model,Model->View的手動(dòng)同步邏輯,造成Presenter比較笨重,維護(hù)起來(lái)會(huì)比較困難。
Supervising Controller模式中,Presenter會(huì)把一部分簡(jiǎn)單的同步邏輯交給View自己去做,Presenter只負(fù)責(zé)比較復(fù)雜的、高層次的UI操作,所以可以把它看成一個(gè)Supervising Controller。
因?yàn)镾upervising Controller用得比較少,MVVM可以看作是一種特殊的MVP(Passive View)模式,或者說(shuō)是對(duì)MVP模式的一種改良。
Model-View-ViewModel模式中,M層數(shù)據(jù)的變化不是通過觀察者模式通知到V層的(即沒有M和V的依賴),也不是通過VM層調(diào)用V層的接口將數(shù)據(jù)傳遞給V層的(這意味著用戶代碼不需要手動(dòng)更新V層)。而是通過在VM層實(shí)現(xiàn)一個(gè)特殊的binder,將數(shù)據(jù)從M層直接綁定到V層。這樣ViewModel層了解Model層,View層了解ViewModel層。
ViewModel充當(dāng)了一個(gè)數(shù)據(jù)轉(zhuǎn)換器的作用。它將Model信息轉(zhuǎn)換為View信息,還將命令從View傳遞到Model。在這里,View可以訪問ViewModel,ViewModel可以訪問Model。
MVVM的調(diào)用關(guān)系和MVP一樣。但是,在ViewModel當(dāng)中會(huì)有一個(gè)叫Binder,或者是Data-binding engine的東西。以前全部由Presenter負(fù)責(zé)的View和Model之間數(shù)據(jù)同步操作交由給Binder處理。你只需要在View的模版語(yǔ)法當(dāng)中,指令式地聲明View上的顯示的內(nèi)容是和Model的哪一塊數(shù)據(jù)綁定的。當(dāng)ViewModel對(duì)進(jìn)行Model更新的時(shí)候,Binder會(huì)自動(dòng)把數(shù)據(jù)更新到View上去,當(dāng)用戶對(duì)View進(jìn)行操作(例如表單輸入),Binder也會(huì)自動(dòng)把數(shù)據(jù)更新到Model上去。這種方式稱為:Two-way data-binding,雙向數(shù)據(jù)綁定??梢院?jiǎn)單而不恰當(dāng)?shù)乩斫鉃橐粋€(gè)模版引擎,但是會(huì)根據(jù)數(shù)據(jù)變更實(shí)時(shí)渲染。
MVVM把View和Model的同步邏輯自動(dòng)化了。以前Presenter負(fù)責(zé)的View和Model同步不再手動(dòng)地進(jìn)行操作,而是交由框架所提供的Binder進(jìn)行負(fù)責(zé)。只需要告訴Binder,View顯示的數(shù)據(jù)對(duì)應(yīng)的是Model哪一部分即可。
雙向綁定技術(shù),當(dāng)Model變化時(shí),View-Model會(huì)自動(dòng)更新,View也會(huì)自動(dòng)變化。很好做到數(shù)據(jù)的一致性,不用擔(dān)心,在模塊的這一塊數(shù)據(jù)是這個(gè)值,在另一塊就是另一個(gè)值了。所以 MVVM模式有些時(shí)候又被稱作:model-view-binder模式。
提高可維護(hù)性。解決了MVP大量的手動(dòng)View和Model同步的問題,提供雙向綁定機(jī)制。提高了代碼的可維護(hù)性。
簡(jiǎn)化測(cè)試。因?yàn)橥竭壿嬍墙挥葿inder做的,View跟著Model同時(shí)變更,所以只需要保證Model的正確性,View就正確。大大減少了對(duì)View同步更新的測(cè)試。
過于簡(jiǎn)單的圖形界面不適用,或說(shuō)牛刀殺雞。
對(duì)于大型的圖形應(yīng)用程序,視圖狀態(tài)較多,ViewModel的構(gòu)建和維護(hù)的成本都會(huì)比較高。
數(shù)據(jù)綁定的聲明是指令式地寫在View的模版當(dāng)中的,這些內(nèi)容是沒辦法去打斷點(diǎn)debug的。
一個(gè)大的模塊中model也會(huì)很大,雖然使用方便了也很容易保證了數(shù)據(jù)的一致性,當(dāng)時(shí)長(zhǎng)期持有,不釋放內(nèi)存就造成了花費(fèi)更多的內(nèi)存。
數(shù)據(jù)雙向綁定不利于代碼重用。客戶端開發(fā)最常用的重用是View,但是數(shù)據(jù)雙向綁定技術(shù),讓你在一個(gè)View都綁定了一個(gè)model,不同模塊的model都不同。那就不能簡(jiǎn)單重用View了。
如有更新,只在原文進(jìn)行:再談MV*(MVVM MVP MVC)模式的設(shè)計(jì)原理-封裝與解耦,如果不妥之處,親留言告知。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。