MVC演化
Classic MVC
Classic MVC 大概上世紀(jì)七十年代,Xerox PARC的Trygve提出了MVC的概念。
并應(yīng)用在Smalltalk系統(tǒng)中,為了和其它類(lèi)型的MVC加以區(qū)分,歷史上習(xí)慣的稱(chēng)之為Classic MVC。
Classic Mvc模式
Model:封裝領(lǐng)域數(shù)據(jù)及邏輯
View:查詢領(lǐng)域數(shù)據(jù)并展現(xiàn)給用戶
Conctroller:截獲用戶請(qǐng)求并改變領(lǐng)域數(shù)據(jù)
從依賴(lài)關(guān)系看,Model不依賴(lài)View和Controller,而View和Controller依賴(lài)Model。
Classic MVC關(guān)注兩個(gè)分離:
從Model中分離View
從View中分離Controller
從Model中分離View,主要基于以下幾點(diǎn)考慮:
不同的關(guān)注點(diǎn):Model關(guān)注內(nèi)在的不可視的邏輯,而View關(guān)注外在的可視的邏輯。
多種表現(xiàn)形式:同一個(gè)Model往往需要多種View表現(xiàn)形式,如文本、圖像。
提高可測(cè)試性:相對(duì)Model而言,View是不容易測(cè)試的。
從View中分離Controller就不那么重要了。
開(kāi)發(fā)軟件的時(shí)代,View和Controller往往是一一對(duì)應(yīng)的關(guān)系,所以常常把他們合并成為UI,事實(shí)上,當(dāng)時(shí)多數(shù)UI框架都沒(méi)有實(shí)現(xiàn)從View中分離Controller。后來(lái)隨著Web的興起,這種分離(模板技術(shù))才開(kāi)始流行起來(lái)。
本質(zhì)上Classic MVC的結(jié)構(gòu)如下圖所示,之所以說(shuō)本質(zhì)上,是因?yàn)閂iew和Controller其實(shí)是彼此關(guān)聯(lián)的,但這種關(guān)聯(lián)和稍后提到的MVP完全不同,更像是一種框架的副產(chǎn)品,為了避免引起混淆,這里省略了它們,具體參閱:How to use Model-View-Controller (MVC)

圖解:
Controller截獲用戶通過(guò)鼠標(biāo)或鍵盤(pán)發(fā)出的請(qǐng)求,然后改變Model的狀態(tài),Model通過(guò)Observer Synchronization通知View自己的狀態(tài)發(fā)生了變化
View查詢Model展現(xiàn)數(shù)據(jù)。
Classic MVC并不完美,不適用于復(fù)雜的邏輯。
舉個(gè)例子:
用戶通過(guò)鼠標(biāo)拖動(dòng)滾動(dòng)條來(lái)調(diào)整音量大小,如果音量大于某個(gè)數(shù)值,背景色變紅以示提醒。當(dāng)使用Classic MVC的時(shí)候,如何處理背景色變紅的邏輯呢?
有兩個(gè)選擇:
Model觸發(fā)一個(gè)特殊事件,View收到后完成相關(guān)邏輯的處理。但我們前面說(shuō)過(guò),從依賴(lài)關(guān)系上看,Model應(yīng)該完全無(wú)視View的存在。
在View中判斷音量臨界值,達(dá)到后完成相關(guān)邏輯的處理。但我們前面說(shuō)過(guò),View是不容易測(cè)試的,應(yīng)該盡可能減少邏輯處理。
Application Model MVC
大概上世紀(jì)八十年代,ParcPlace從Xerox Parc劃分出來(lái),負(fù)責(zé)Smalltalk的研發(fā)工作,為了適應(yīng)更復(fù)雜的邏輯,開(kāi)發(fā)了Classic MVC的改進(jìn)版,也就是Application Model MVC,在原有架構(gòu)基礎(chǔ)上引入了Application Model,如下圖所示:

圖解:
Application Model在Model和View、Controller之間扮演著一個(gè)中繼者的角色。
接著看前面的例子,既然Model和View都不適合放背景色變紅的邏輯,那么我們可以嘗試把相關(guān)邏輯放在Application Model中實(shí)現(xiàn),當(dāng)用戶通過(guò)鼠標(biāo)調(diào)整音量大小時(shí),Model觸發(fā)一個(gè)普通事件,Application Model攔截到這個(gè)事件,判斷音量是否大于臨界值,如果是就觸發(fā)一個(gè)特殊事件,View收到后完成相關(guān)邏輯的處理。
Application Model MVC雖然看似解決了復(fù)雜邏輯的問(wèn)題,但它仍然存在硬傷:
首先隨著以微軟視窗為主的圖形化操作系統(tǒng)的興起,操作系統(tǒng)本身提供了一套原生的View接口,用來(lái)截獲用戶通過(guò)鼠標(biāo)或鍵盤(pán)發(fā)出的請(qǐng)求。
結(jié)果讓Controller顯得多余了。
其次由于在Application Model MVC中,View的渲染只能通過(guò)事件的方式實(shí)現(xiàn),Application Model不能直接操作View,所以某些情況下不能方便的實(shí)現(xiàn)業(yè)務(wù)邏輯。接著前面說(shuō)的調(diào)節(jié)音量的例子,這次我們加個(gè)新功能,不再通過(guò)鼠標(biāo)拖動(dòng)滾動(dòng)條來(lái)調(diào)整音量大小,而是給出一個(gè)文本框,讓用戶直接通過(guò)鍵盤(pán)輸入阿拉伯?dāng)?shù)字表示音量大小,一旦用戶輸入非法內(nèi)容(比如說(shuō)英文字符),背景色變黃以示警告。問(wèn)題是如果用戶輸入非法內(nèi)容,就不應(yīng)該改變Model的狀態(tài),但不改變Model的狀態(tài),View就沒(méi)有機(jī)會(huì)收到渲染的事件。
MVP
大概上世紀(jì)九十年代,IBM的Mike Potel提出了MVP的概念。與此同時(shí),Smalltalk團(tuán)隊(duì)正在開(kāi)發(fā)新一代框架,當(dāng)他們看到MVP時(shí),發(fā)現(xiàn)它不僅和MVC非常相似,并且很好的解決了復(fù)雜邏輯的問(wèn)題,所以決定使用它,出于復(fù)雜度的關(guān)系,他們簡(jiǎn)化了MVP,最終看上去更像是把原本的MVC扭轉(zhuǎn)了一個(gè)角度,把其中的VC顛倒了一下順序:

圖解:
View截獲用戶請(qǐng)求,然后委派給Presenter,Presenter改變Model的狀態(tài),Model通過(guò)Observer Synchronization通知View自己的狀態(tài)發(fā)生了變化,View查詢Model展現(xiàn)數(shù)據(jù)。
最重要的是一點(diǎn)是Presenter和View彼此持有對(duì)方的引用。雖然View截獲用戶請(qǐng)求,但它并不處理,而是委派給Presenter處理,保證了可測(cè)試性,同時(shí),因?yàn)镻resenter可以直接操作View,不必受限于觀察者模式。
接著前面說(shuō)的調(diào)節(jié)音量的例子,當(dāng)用戶通過(guò)鼠標(biāo)拖動(dòng)滾動(dòng)條來(lái)調(diào)整音量大小時(shí),View截獲請(qǐng)求,并把請(qǐng)求委派給Presenter,如果Presenter發(fā)現(xiàn)音量大于臨界值,直接操作View實(shí)現(xiàn)邏輯;當(dāng)用戶通過(guò)鍵盤(pán)輸入音量大小時(shí),View截獲請(qǐng)求,并把請(qǐng)求委派給Presenter,如果Presenter發(fā)現(xiàn)內(nèi)容非法,直接操作View實(shí)現(xiàn)邏輯。
Martin Fowler分析了MVP的實(shí)現(xiàn)方式,分類(lèi)為Supervising Controller和Passive View。

圖解:
MVP的兩種分類(lèi):Supervising Controller和Passive View
二者的區(qū)別在于Model和View是否有聯(lián)系,在Supervising Controller的實(shí)現(xiàn)中,View可以查詢Model,Model狀態(tài)發(fā)生變化的話會(huì)通知View,而在Passive View的實(shí)現(xiàn)中,View不可以查詢Model,Model狀態(tài)發(fā)生變化的話會(huì)通知Presenter,由Presenter完成View的渲染。比較而言,Passive View的可測(cè)試性更好一些,但Presenter的代碼量相應(yīng)大些。
前面我們討論了MVC到MVP的演化史,隨著Web的興起,人們開(kāi)始把MVC,MVP等知識(shí)應(yīng)用到Web環(huán)境下,但Web環(huán)境有其特殊性,最重要的一點(diǎn)就是HTTP是無(wú)狀態(tài)的,每次請(qǐng)求都是獨(dú)立的,所以不可能實(shí)現(xiàn)觀察者模式。
Web MVC
Java是Web MVC最早的實(shí)踐者,開(kāi)發(fā)出Model 2,使用JavaBean,JSP,Servlet分別對(duì)應(yīng)MVC中的三個(gè)組成部分,緊接著Structs的出現(xiàn)開(kāi)始讓大眾注意到Web MVC,不過(guò)真正讓W(xué)eb MVC流行起來(lái)的卻是Ruby社區(qū)的Rails,其大致流程如下圖所示:

圖解:
一個(gè)典型的Web MVC流程
Controller截獲用戶發(fā)出的請(qǐng)求
Controller調(diào)用Model完成狀態(tài)的讀寫(xiě)操作
Controller把數(shù)據(jù)傳遞給View
View渲染最終結(jié)果并呈獻(xiàn)給用戶
在Classic MVC中,Controler可以改變Model的狀態(tài),View可以查詢Model的狀態(tài),所以說(shuō)對(duì)Model而言,Controller和View的地位是平等的,不過(guò)在Web MVC中,Controller變成了中繼者,主要工作是協(xié)調(diào)Model和View,如此看來(lái),Web MVC中的Controller等同于MVP中的Presenter。那為什么不叫Web MVP,而稱(chēng)之為Web MVC?這是因?yàn)榻孬@請(qǐng)求的是Controller而不是View。
Python社區(qū)的Django框架宣稱(chēng)自己使用的是MTV,其實(shí)質(zhì)仍然是Web MVC。
Web MVP
在Desktop的時(shí)代,微軟通過(guò)WinForms實(shí)現(xiàn)MVP,把組件化編程發(fā)揮到了極致,大大提升了開(kāi)發(fā)效率,隨著Web的興起,微軟希望延續(xù)這樣的編程模式,所以使用WebForms實(shí)現(xiàn)了Web MVP,引入了CodeBehind,ViewState等設(shè)計(jì)概念。WebForms的優(yōu)點(diǎn)和缺點(diǎn)都很突出,篇幅所限,具體的描述大家可以參考下面鏈接:
- 為WebForms說(shuō)幾句話,以及一些ASP.NET開(kāi)發(fā)上的經(jīng)驗(yàn)(1)
- 為WebForms說(shuō)幾句話,以及一些ASP.NET開(kāi)發(fā)上的經(jīng)驗(yàn)(2)
- 為WebForms說(shuō)幾句話,以及一些ASP.NET開(kāi)發(fā)上的經(jīng)驗(yàn)(3)
注:微軟推出了ASP.NET MVC向Web MVC靠攏,似乎要兩手抓兩手都要硬。

圖解:
微軟Web MVP vs Web MVC。注意截獲請(qǐng)求的是Controller還是View!

浙公網(wǎng)安備 33010602011771號(hào)