MVC少孝,MVP 和 MVVM 模式如何選擇

前言

做客戶端開發(fā)图仓、前端開發(fā)對MVC、MVP纲岭、MVVM這些名詞不了解也應(yīng)該大致聽過魏铅,都是為了解決圖形界面應(yīng)用程序復(fù)雜性管理問題而產(chǎn)生的應(yīng)用架構(gòu)模式勉吻。

GUI程序所面臨的問題

圖形界面的應(yīng)用程序提供給用戶可視化的操作界面谭梗,這個界面提供給數(shù)據(jù)和信息忘晤。用戶輸入行為(鍵盤,鼠標(biāo)等)會執(zhí)行一些業(yè)務(wù)邏輯激捏,可能會導(dǎo)致對應(yīng)用程序數(shù)據(jù)的變更设塔,數(shù)據(jù)的變更自然需要用戶界面的同步變更以提供最準(zhǔn)確的信息。例如用戶對一個電子表格重新排序的操作远舅,應(yīng)用程序需要響應(yīng)用戶操作闰蛔,對數(shù)據(jù)進(jìn)行排序,然后需要同步到界面上图柏。

在開發(fā)應(yīng)用程序的時候钞护,以求更好的管理應(yīng)用程序的復(fù)雜性,基于職責(zé)分離(Speration of Duties)的思想都會對應(yīng)用程序進(jìn)行分層爆办。在開發(fā)圖形界面應(yīng)用程序的時候,會把管理用戶界面的層次稱為View课梳,應(yīng)用程序的數(shù)據(jù)為Model(注意這里的Model指的是Domain Model距辆,這個應(yīng)用程序?qū)π枰鉀Q的問題的數(shù)據(jù)抽象,不包含應(yīng)用的狀態(tài)暮刃,可以簡單理解為對象)跨算。Model層對應(yīng)用程序的業(yè)務(wù)邏輯無知,只保存數(shù)據(jù)結(jié)構(gòu)和提供數(shù)據(jù)操作的接口

有了View和Model的分層椭懊,那么就有了兩個問題:

1诸蚕、響應(yīng)用戶操作的業(yè)務(wù)邏輯(例如排序)的管理。
2、View如何同步Model的變更背犯。

帶著這兩個問題開始探索MV模式坏瘩,會發(fā)現(xiàn)這些模式之間的差異可以歸納為對這兩個問題處理的方式的不同。而幾乎所有的MV模式都是經(jīng)典的Smalltalk-80 MVC的修改版漠魏。

MVC的依賴關(guān)系

MVC出了把應(yīng)用程序分成View倔矾、Model層,還額外的加了一個Controller層柱锹,它的職責(zé)就是專門管理應(yīng)用程序的業(yè)務(wù)邏輯哪自。Model、View禁熏、Controller三個層次的依賴關(guān)系如下:


Controller和View都依賴Model層壤巷,Controller和View可以互相依賴。在一些網(wǎng)上的資料Controller和View之間的依賴關(guān)系可能不一樣瞧毙,有些是單向依賴胧华,有些是雙向依賴,這個其實(shí)關(guān)系不大升筏,后面會看到它們的依賴關(guān)系都是為了把處理用戶行為觸發(fā)的業(yè)務(wù)邏輯的處理權(quán)交給Controller撑柔。

MVC的調(diào)用關(guān)系

用戶的對View操作以后,View捕獲到這個操作您访,會把處理的權(quán)利交移給Controller(Pass calls)铅忿;Controller接著會執(zhí)行相關(guān)的業(yè)務(wù)邏輯,這些業(yè)務(wù)邏輯可能需要對Model進(jìn)行相應(yīng)的操作灵汪;當(dāng)Model變更了以后檀训,會通過觀察者模式(Observer Pattern)通知View;View通過觀察者模式收到Model變更的消息以后享言,會向Model請求最新的數(shù)據(jù)峻凫,然后重新更新界面。如下圖:

看似沒有什么特別的地方览露,但是由幾個需要特別關(guān)注的關(guān)鍵點(diǎn):

1荧琼、View是把控制權(quán)交移給Controller,自己不執(zhí)行業(yè)務(wù)邏輯差牛。
2命锄、Controller執(zhí)行業(yè)務(wù)邏輯并且操作Model,但不會直接操作View偏化,可以說它是對View無知的脐恩。
3、View和Model的同步消息是通過觀察者模式進(jìn)行侦讨,而同步操作是由View自己請求Model的數(shù)據(jù)然后對視圖進(jìn)行更新驶冒。

需要特別注意的是MVC模式的精髓在于第三點(diǎn):Model的更新是通過觀察者模式告知View的苟翻,具體表現(xiàn)形式可以是Pub/Sub或者是觸發(fā)Events。而網(wǎng)上很多對于MVC的描述都沒有強(qiáng)調(diào)這一點(diǎn)骗污。通過觀察者模式的好處就是:不同的MVC三角關(guān)系可能會有共同的Model崇猫,一個MVC三角中的Controller操作了Model以后,兩個MVC三角的View都會接受到通知身堡,然后更新自己邓尤。保持了依賴同一塊Model的不同View顯示數(shù)據(jù)的實(shí)時性和準(zhǔn)確性。我們每天都在用的觀察者模式贴谎,在幾十年前就已經(jīng)被大神們整合到MVC的架構(gòu)當(dāng)中汞扎。

MVC的優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

1、把業(yè)務(wù)邏輯全部分離到Controller中擅这,模塊化程度高澈魄。當(dāng)業(yè)務(wù)邏輯變更的時候,不需要變更View和Model仲翎,只需要Controller換成另外一個Controller就行了(Swappable Controller)痹扇。
2、觀察者模式可以做到多視圖同時更新溯香。

缺點(diǎn):

1鲫构、Controller測試?yán)щy。因?yàn)橐晥D同步操作是由View自己執(zhí)行玫坛,而View只能在有UI的環(huán)境下運(yùn)行结笨。在沒有UI環(huán)境下對Controller進(jìn)行單元測試的時候,Controller業(yè)務(wù)邏輯的正確性是無法驗(yàn)證的:Controller更新Model的時候湿镀,無法對View的更新操作進(jìn)行斷言炕吸。
2、View無法組件化勉痴。View是強(qiáng)依賴特定的Model的赫模,如果需要把這個View抽出來作為一個另外一個應(yīng)用程序可復(fù)用的組件就困難了。因?yàn)椴煌绦虻牡腄omain Model是不一樣的

MVP

1蒸矛、Passive View

MVP(Passive View)的依賴關(guān)系

MVP模式把MVC模式中的Controller換成了Presenter瀑罗。MVP層次之間的依賴關(guān)系如下:



MVP打破了View原來對于Model的依賴,其余的依賴關(guān)系和MVC模式一致雏掠。

MVP(Passive View)的調(diào)用關(guān)系

既然View對Model的依賴被打破了廓脆,那View如何同步Model的變更?看看MVP的調(diào)用關(guān)系:



和MVC模式一樣磁玉,用戶對View的操作都會從View交移給Presenter。Presenter同樣的會執(zhí)行相應(yīng)的業(yè)務(wù)邏輯驾讲,并且對Model進(jìn)行相應(yīng)的操作蚊伞;而這時候Model也是通過觀察者模式把自己變更的消息傳遞出去席赂,但是是傳給Presenter而不是View。Presenter獲取到Model變更的消息以后时迫,通過View提供的接口更新界面颅停。

關(guān)鍵點(diǎn):

1、View不再負(fù)責(zé)同步的邏輯掠拳,而是由Presenter負(fù)責(zé)癞揉。Presenter中既有業(yè)務(wù)邏輯也有同步邏輯。
2溺欧、View需要提供操作界面的接口給Presenter進(jìn)行調(diào)用喊熟。(關(guān)鍵)

對比在MVC中,Controller是不能操作View的姐刁,View也沒有提供相應(yīng)的接口芥牌;而在MVP當(dāng)中,Presenter可以操作View聂使,View需要提供一組對界面操作的接口給Presenter進(jìn)行調(diào)用壁拉;Model仍然通過事件廣播自己的變更,但由Presenter監(jiān)聽而不是View柏靶。

MVP(Passive View)的優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

1弃理、便于測試。Presenter對View是通過接口進(jìn)行屎蜓,在對Presenter進(jìn)行不依賴UI環(huán)境的單元測試的時候痘昌。可以通過Mock一個View對象梆靖,這個對象只需要實(shí)現(xiàn)了View的接口即可控汉。然后依賴注入到Presenter中,單元測試的時候就可以完整的測試Presenter業(yè)務(wù)邏輯的正確性返吻。這里根據(jù)上面的例子給出了Presenter的單元測試樣例姑子。
2、View可以進(jìn)行組件化测僵。在MVP當(dāng)中街佑,View不依賴Model。這樣就可以讓View從特定的業(yè)務(wù)場景中脫離出來捍靠,可以說View可以做到對業(yè)務(wù)邏輯完全無知沐旨。它只需要提供一系列接口提供給上層操作。這樣就可以做高度可復(fù)用的View組件榨婆。

缺點(diǎn):

1磁携、Presenter中除了業(yè)務(wù)邏輯以外,還有大量的View->Model良风,Model->View的手動同步邏輯谊迄,造成Presenter比較笨重闷供,維護(hù)起來會比較困難。

MVVM

ViewModel

MVVM代表的是Model-View-ViewModel统诺,這里需要解釋一下什么是ViewModel歪脏。ViewModel的含義就是 "Model of View",視圖的模型粮呢。它的含義包含了領(lǐng)域模型(Domain Model)和視圖的狀態(tài)(State)婿失。 在圖形界面應(yīng)用程序當(dāng)中,界面所提供的信息可能不僅僅包含應(yīng)用程序的領(lǐng)域模型啄寡。還可能包含一些領(lǐng)域模型不包含的視圖狀態(tài)豪硅,例如電子表格程序上需要顯示當(dāng)前排序的狀態(tài)是順序的還是逆序的,而這是Domain Model所不包含的这难,但也是需要顯示的信息舟误。

可以簡單把ViewModel理解為頁面上所顯示內(nèi)容的數(shù)據(jù)抽象,和Domain Model不一樣姻乓,ViewModel更適合用來描述View嵌溢。

MVVM的依賴

MVVM的依賴關(guān)系和MVP依賴,只不過是把P換成了VM蹋岩。

MVVM的調(diào)用關(guān)系

MVVM的調(diào)用關(guān)系和MVP一樣赖草。但是,在ViewModel當(dāng)中會有一個叫Binder剪个,或者是Data-binding engine的東西秧骑。以前全部由Presenter負(fù)責(zé)的View和Model之間數(shù)據(jù)同步操作交由給Binder處理。你只需要在View的模版語法當(dāng)中扣囊,指令式地聲明View上的顯示的內(nèi)容是和Model的哪一塊數(shù)據(jù)綁定的乎折。當(dāng)ViewModel對進(jìn)行Model更新的時候,Binder會自動把數(shù)據(jù)更新到View上去侵歇,當(dāng)用戶對View進(jìn)行操作(例如表單輸入)骂澄,Binder也會自動把數(shù)據(jù)更新到Model上去。這種方式稱為:Two-way data-binding惕虑,雙向數(shù)據(jù)綁定坟冲。可以簡單而不恰當(dāng)?shù)乩斫鉃橐粋€模版引擎溃蔫,但是會根據(jù)數(shù)據(jù)變更實(shí)時渲染健提。


也就是說,MVVM把View和Model的同步邏輯自動化了伟叛。以前Presenter負(fù)責(zé)的View和Model同步不再手動地進(jìn)行操作私痹,而是交由框架所提供的Binder進(jìn)行負(fù)責(zé)。只需要告訴Binder,View顯示的數(shù)據(jù)對應(yīng)的是Model哪一部分即可紊遵。

MVVM的優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

1雹锣、提高可維護(hù)性。解決了MVP大量的手動View和Model同步的問題癞蚕,提供雙向綁定機(jī)制。提高了代碼的可維護(hù)性辉哥。
2桦山、簡化測試。因?yàn)橥竭壿嬍墙挥葿inder做的醋旦,View跟著Model同時變更恒水,所以只需要保證Model的正確性,View就正確饲齐。大大減少了對View同步更新的測試钉凌。

缺點(diǎn):

1、過于簡單的圖形界面不適用捂人,或說牛刀殺雞御雕。
2、對于大型的圖形應(yīng)用程序滥搭,視圖狀態(tài)較多酸纲,ViewModel的構(gòu)建和維護(hù)的成本都會比較高。
3瑟匆、數(shù)據(jù)綁定的聲明是指令式地寫在View的模版當(dāng)中的闽坡,這些內(nèi)容是沒辦法去打斷點(diǎn)debug的。

結(jié)語

可以看到愁溜,從MVC->MVP->MVVM疾嗅,就像一個打怪升級的過程。后者解決了前者遺留的問題冕象,把前者的缺點(diǎn)優(yōu)化成了優(yōu)點(diǎn)代承。同樣的Demo功能,代碼從最開始的一堆文件交惯,優(yōu)化成了最后只需要20幾行代碼就完成次泽。MV*模式之間的區(qū)分還是蠻清晰的,希望可以給對這些模式理解比較模糊的同學(xué)帶來一些參考和思路席爽。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末意荤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子只锻,更是在濱河造成了極大的恐慌玖像,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異捐寥,居然都是意外死亡笤昨,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門握恳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瞒窒,“玉大人,你說我怎么就攤上這事乡洼〕绮茫” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵束昵,是天一觀的道長拔稳。 經(jīng)常有香客問我,道長锹雏,這世上最難降的妖魔是什么巴比? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮礁遵,結(jié)果婚禮上轻绞,老公的妹妹穿的比我還像新娘。我一直安慰自己榛丢,他們只是感情好铲球,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著晰赞,像睡著了一般稼病。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上掖鱼,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天然走,我揣著相機(jī)與錄音,去河邊找鬼戏挡。 笑死芍瑞,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的褐墅。 我是一名探鬼主播拆檬,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼妥凳!你這毒婦竟也來了竟贯?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤逝钥,失蹤者是張志新(化名)和其女友劉穎屑那,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡持际,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年沃琅,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蜘欲。...
    茶點(diǎn)故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡益眉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出姥份,到底是詐尸還是另有隱情呜叫,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布殿衰,位于F島的核電站,受9級特大地震影響盛泡,放射性物質(zhì)發(fā)生泄漏闷祥。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一傲诵、第九天 我趴在偏房一處隱蔽的房頂上張望凯砍。 院中可真熱鬧,春花似錦拴竹、人聲如沸悟衩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽座泳。三九已至,卻和暖如春幕与,著一層夾襖步出監(jiān)牢的瞬間挑势,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工啦鸣, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留潮饱,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓诫给,卻偏偏與公主長得像香拉,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子中狂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容