在Java平台,基於Spring等技術的MVC框架已經走向成熟;在.NET平台,微軟也推出了MVC、MVP Framework,MVP不同於MVC的地方,關鍵在於,View不再顯示的依賴於Business Logic Controller,而是依賴於一個業務邏輯抽象接口,關注於View的解藕。所以區分MVP與MVC的關鍵在於View是否依賴於某一具體的業務對象。
Model View Presenter vs Model View Controller
在N層體系結構中MVC/P模式僅僅只是用於表示層(presentation layer),理解這一點很重要。這兩個模式並不是關於怎么構建數據層(data layer)和服務層(service layer)的,而是關於怎么將數據(data)從用戶接口(view)中分離出來,以及用戶接口如何與數據進行交互的。這些模式的使用解除了你的程序中表示層對數據和控制邏輯的依賴,從而可以自由的變更表示層。
MVC(Model View Controller)模式處理過程
- 為了使得視圖接口可以與模型和控制器進行交互,控制器執行一些初始化事件
- 用戶通過視圖(用戶接口)執行一些操作
- 控制器處理用戶行為(可以用觀察着模式實現)並通知模型進行更新
- 模型引發一些事件,以便將改變發告知視圖
- 視圖處理模型變更的事件,然后顯示新的模型數據
- 用戶接口等待用戶的進一步操作
這一模式的有以下幾個要點:
- 視圖並不使用控制器去更新模型。控制器負責處理從視圖發送過來的用戶操作並通過與模型的交互進行數據的更新
- 控制器可以和視圖融合在一塊。Visual Studio.NET中對Windows Forms的默認處理方式就是這樣的。
【譯注:比如雙擊一個Button,然后在它的事件里寫處理邏輯,然后將處理的數據寫回模型中。這里處理邏輯時間應該是控制器的功能,但是我們並沒有專門寫一個控制器來做這件事情而是接受了VS.NET IDE的默認處理方式,將它寫在Form的代碼中,而這里的Form在MVC中它就是一個View。所以這說VS.NET IDE默認的處理方式是將把控制器和視圖融合在一起的。】
- 控制器不包含對視圖的渲染邏輯(rendering logic)
“主動—MVC”模式,也是通常意義下的MVC模式
【譯注:為什么說是主動的?View不是等Controller通知它Model更新了然后才從Model取數據並更新顯示,而是自己監視Model的更新(如果用觀察者模式)或主動詢問Model是否更新。前面那種等待Controller通知的方式是下面所介紹的“被動—MVC”的實現方式。】
“被動—MVC”模式與主動MVC的區別在於:
- 模型對視圖和控制器一無所知,它僅僅是被它們使用
- 控制器使用視圖,並通知它更新數據顯示
- 視圖僅僅是在控制器通知它去模型取數據的時候它才這么做(視圖並不會訂閱或監視模型的更新)
- 控制器負責處理模型數據的變化
- 控制器可以包含對視圖的渲染邏輯

現在我們來看看MVC應用程序的執行過程:
- 當用戶發出請求時,請求首先由UrlRoutingModule 對象處理,這個對象是一個HTTP模塊(HTTP module)。這個對象在分析請求后,查找第一個與當前請求匹配的route對象(route object)。 route對象是實現了RouteBase的類,通常都是Route類的實例。
- 如果沒找到任何吻合的route對象,UrlRoutingModule 就不再處理,而由ASP.NET的標准流程或IIS繼續處理。
- 如果找到了一個Route對象,UrlRoutingModule會從Route對象中獲取IRouteHandler對象實例。IRouteHandler 對象通常都是MvcRouteHandler的實例,它會創建IHttpHandler對象(默認情形下就是MvcHandler的實例),並傳遞給IHttpContext 對象。由MvcHandler的實例選擇控制器,並最終讓這個控制器處理請求。注意:對於IIS6,要把.mvc文件擴展名映射到ASP.NET_ISAPI.DLL,IIS7則不用配置。
模塊(module)和處理器(handler)是MVC框架的入口點,他們負責以下工作:
- 從MVC Web應用程序挑選恰當的控制器
- 獲取特定的控制器對象實例
- 調用控制器的Execute方法
執行過程:
- 首次接收到對應用程序的請求
在Global.asax文件中,Route對象被加入到RouteTable集合。
- route操作
UrlRoutingModule從RouteTable中查找首個匹配的Route對象,創建RouteData對象,用RouteData對象創建RequestContext對象。
- 創建MVC請求處理器
MvcRouteHandler對象實例創建MvcHandler類的實例,然后向它傳遞RequestContext實例。
- 創建控制器
MvcHandler 通過RequestContext實例找到IControllerFactory 對象,用它來創建控制器對象實例。IControllerFactory 對象通常都是DefaultControllerFactory的實例。如果沒有找到對應的控制器,將返回HTTP500錯誤。
- 執行控制器
MvcHandler調用控制器的Execute方法。
- 調用動作方法
多數控制器類都是從Controller 基類繼承來的,凡是這類控制器,其內部的ControllerActionInvoker對象負責判斷應該調用哪個動作方法,並由它來調用。
這兩種模式中三個部分的一般理解
1、模型(Model)表示數據模型和業務邏輯(business logic)。模型並不總是DataSet,DataTable之類的東西,它代表着一類組件(components)或類(class),這些組件或類可以向外部提供數據,同時也能從外部獲取數據並將這些數據存儲在某個地方。簡單的理解,可以把模型想象成“外觀類(facade class)”。【譯注:這里的外觀是指“外觀模式”中所說的外觀。外觀的一般作用是為一個復雜的子系統提供高層次的簡單易用的訪問接口】,可以參看下面的圖來理解它的原理:
2、視圖(View)將數據層現給用戶。一般的視圖都只是包含用戶界面(UI),而不包含界面邏輯。比如,Asp.net中包含控件的頁面(Page)就是一個視圖。視圖可以從模型中讀取數據,但是不能修改或更新模型。
3、層現器(Presenter)/控制器(Controller)包含了根據用戶在視圖中的行為去更新模型的邏輯。視圖僅僅只是將用戶的行為告知控制器,而控制器負責從視圖中取得數據然后發送給模型。
MVC/P模式的核心是為了將模型從視圖/控制器中分離出來,從而使得模型獨立於它們,因此模型不包含對視圖和控制的引用。
MVP模式
與“被動—MVC模式”很接近,區別在於“視圖並不使用模型”。在MVP模式中視圖和模型是完全分離的,他們通過Presenter進行交互。
Presenter與控制器非常相似,但是它們也有一些的區別:
- Presenter處理視圖發送過來的用戶操作(在MVC中視圖自己處理了這些操作)
- 它用更新過的數據去更新模型(在被動MVC中控制器只是通知視圖去更新過的模型中去取新的數據,而主動MVC中模型通知視圖去更新顯示,控制器不需要做工作)
- 檢查模型的更新(與被動MVC一樣)
- (與MVC的主要區別)從模型中取數據然后將它們發送到視圖中
- (與MVC的主要區別)將所做的更新告知視圖
- (與MVC的區別)用Presenter渲染視圖
MVP的優勢
- 模型與視圖完全分離,我們可以修改視圖而不影響模型
- 可以更高效地使用模型,因為所以的交互都發生在一個地方——Presenter內部
- 我們可以將一個Presener用於多個視圖,而不需要改變Presenter的邏輯。這個特性非常的有用,因為視圖的變化總是比模型的變化頻繁。
- 如果我們把邏輯放在Presenter中,那么我們就可以脫離用戶接口來測試這些邏輯(單元測試)
MVP的缺點
由於對視圖的渲染放在了Presenter中,所以視圖和Persenter的交互會過於頻繁。還有一點你需要明白,如果Presenter過多地渲染了視圖,往往會使得它與特定的視圖的聯系過於緊密。一旦視圖需要變更,那么Presenter也需要變更了。比如說,原本用來呈現html的Presenter現在也需要用於呈現其他文件了,那么視圖很有可能也需要變更。
