ASP.NET 表示模式-MVP和MVC

 

原始 MVC 模式
MVC 模式的發明要追溯到 1979 年,當時將該模式作爲一種遠離全能、自治前端的方法。自治視圖是一個類,可顯示目錄、維護視圖的狀態信息,並整合了整個邏輯可以始終處理任何用戶操作。
此代碼段爲自治視圖奠定了基礎:
 
   void Button1_Click(object sender, EventArgs e)
   {
       // Perform any required action. All the code you 
       // need to handle the event goes here. A page 
       // built in this way is an autonomous view.
       // MVC fights autonomous views.
   }
使用這樣的整體化視圖,您幾乎無法構建獨立於基礎層的可測試表示層。應用關注點分離 (SoC) 的概念可幫助您獲取任一組件的低級耦合和高度聚合的正確組合,因爲它使您可以將各種功能保留在其各自的層中,而不是將它們混合到一起。其次,應用 SoC,可以更輕鬆地實現導航工作流以確定接下來顯示的頁面。
通過聯機方式可以閱讀這篇介紹 MVC 方法的原創作品“如何使用模型-視圖-控制器”。如果您尚未閱讀此文章,我建議您無論是否熟悉 MVC 原理,都要看看這篇文章。現在,MVC 被認爲是構建表示層的一種模式,但是它起初是用來構建完整應用程序的,從這個角度可以幫助您理解 MVC。
MVC 模式的定義並不嚴謹,因此實施細節時很多地方都需要架構師自行斟酌。這也許是爲什麼會存在這麼多 MVC 變體的原因。
MVC 將應用程序拆分爲三部分:模型、視圖和控制器。模型引用應用程序數據,管理應用程序的功能並通知狀態視圖的更改。視圖負責要向用戶顯示的內容。最後,控制器將用戶操作映射到模型上的操作,然後更新當前視圖或選擇下一視圖。這三個部分通常稱爲 MVC 的三層架構。圖 3 以圖形方式顯示了自治視圖和 MVC 應用程序的比較結果。
圖 3 從自治視圖到 MVC
在 MVC 中,用戶與視圖交互,然後視圖捕獲操作(如按鈕單擊)並將其轉發給控制器。控制器確定要執行的操作並通過與模型交互來執行該操作。此模型實際上就是業務層加上一些額外的功能。特別是,模型會通知視圖更新 UI 時可能需要的更改。
雖然模型不瞭解視圖的任何詳細信息,但是模型和視圖之間存在“觀察者”關係。換句話說,視圖保留對模型的引用並將其自身註冊到模型以接收更改通知。接收到通知後,視圖將從模型中獲取新數據並對 UI 進行更新。圖 4 演示了 MVC 交互的順序圖。請注意,在一些 MVC 實現中,由控制器通知視圖所做的更改。
圖 4 標準 MVC 交互(單擊圖像可查看大圖)

Model2:MVC 的 Web 變體
設計 MVC 的初衷是面向桌面應用程序,但是由於其設計比較鬆散,因此被稍加修改應用到了 Web 上。常用的 MVC 模式的 Web 變體是 Model2。Model2 是現在的 ASP.NET MVC Framework 使用的模式的曾用名。
Model2 模式通過瀏覽器向用戶顯示視圖。用戶操作由瀏覽器捕獲,然後轉換爲新的 HTTP 請求。通過這種方式,請求從瀏覽器傳到 Web 服務器中的特定組件(稱爲前端控制器)。前端控制器協調對 Web 應用程序提出的所有請求。
在 ASP.NET 中,此前端控制器採用 URL 路由 HTTP 模塊這種形式。HTTP 模塊捕獲請求,然後將其路由到相應的控制器以執行請求操作。返回操作方法後,控制器將對視圖進行排序以刷新併爲新 UI 傳遞新數據。視圖輸出被前端控制器 HTTP 模塊捕獲,然後發送回瀏覽器。
圖 5 顯示典型 Model2 交互的順序圖。您應該注意到此圖中僅包含常規步驟。例如,在該模式的 ASP.NET MVC 實現中,URL 路由組件除使用控制器外,還執行其他一些任務。
圖 5 ASP.NET MVC Framework 中的 Model2 交互(單擊圖像可查看大圖)
原始 MVC 和 Model2 有些差別。您可以看到,視圖和模型之間沒有任何聯繫,而在前面提到的 MVC 原始設計中兩者間存在“觀察者”關係。用戶操作也不是由視圖來捕獲和處理。控制器呈現視圖並向其顯式傳遞顯示數據。
在 ASP.NET 中,當提及 MVC 時,應該指定所說的是 Model2 還是手動實現的 MVC,本專欄開始曾簡要介紹過此內容。(如果希望瞭解更多信息,請閱讀《MSDN 雜誌》上的文章 ASP.NET MVC Framework

ASP.NET MVC Framework 和手動 MVC
爲了使每個頁面(或一組頁面)都擁有一個控制器類,使用 ASP.NET MVC Framework 和手動實現 MVC 模式這兩種方法有什麼區別嗎?在 SoC 方面,我沒有發現任何顯著差別。在以上兩種情況下,您都有一個完全獨立於視圖和代表業務層或服務層網關的模型的控制器類。
在可測試性方面,Model2 模式要優於 MVC 模式的原始設計,因爲前者出色地強制分開了視圖和模型,且視圖非常精簡,僅這一個方面就可以有效地測試爲 ASP.NET MVC Framework 編寫的代碼。此外,在 Model2 中有一種可在視圖和控制器之間建立的不嚴格的約定。在 ASP.NET MVC Framework 中,此約定由 ViewData 容器對象或視圖類的 ViewPage<T> 基類表示,其中後者表示效果更好。
與 ASP.NET Web 窗體相比,Model2 實現執行請求操作的速度更快。在 Model2 實現中,您只需要一個用來處理 HTTP 請求和調用控制器的組件,無需動態創建頁面類;查找控制器依據的算法與 Web 窗體方案中查找 HTTP 處理程序相比簡單得多;同樣,您也不需要使用頁面生命週期、視圖狀態或服務器控件。在 Model2 實現中,如 ASP.NET MVC Framework,您會擁有一個更靈活的運行時環境。接下來我們將進一步探討此內容。
在通過 Web 窗體編程模型實施的 MVC 方案中,所有用戶操作均源於 HTTP 發佈。Web 服務器捕獲這些請求,然後將其映射到 Page 類。Page 類歷經其整個生命週期,如圖 1 所示。然後,Page 類找到正確的控制器並調用一種方法。執行此方法會修改模型。其餘的頁面生命週期涉及到刷新視圖。
在使用 ASP.NET MVC Framework 實施的 Model2 方案中,生成下一個視圖的過程更簡單。URL 路由模塊解析 URL,並根據 URL 確定要使用的控制器,然後在所選的控制器上調用操作,該控制器爲新視圖收集新數據並傳遞此信息。該視圖收集隨後作爲對捕獲請求的響應返回到瀏覽器的 HTML。此視圖是被動主題,實際上不需要進行測試。但是,您需要對控制器進行重點測試。
Model2 是改善應用程序可測試性的優先選擇。但是,如果您仍需要 Web 窗體運行時環境來支持會話、緩存、服務器控件甚至視圖狀態(隨 MVC 模式一起提供),該怎麼辦?這是否意味着您不得不放棄 SoC 和可測試性?當然不是。您可以選擇使用我在開始提到的 MVC 的另一變體 — MVP 模式。它適用於 Web 應用程序,且不需要臨時運行時。

MVP 模式
MVC 的原始設計有一個重要缺陷:更新視圖的機制。您在圖 4 中看到的信息流顯示視圖將用戶操作傳送到控制器,而從模型接收更改通知。接下來,視圖需要完全瞭解模型才能獲取更新的數據以及進行刷新。MVP 是 MVC 的變體,能夠更清晰地分離三層架構中的每個元素。圖 6 顯示了 MVP 模型中各部分之間的典型交互。
圖 6 運行中的 MVP 模式(單擊圖像可查看大圖)
在 MVP 中,視圖將用戶輸入轉發給表示器,然後從表示器接收新數據以進行更新。反過來,表示器通過與模型交互來處理請求。
在原始 MVC 中,沒有任何明確約定規定視圖需要哪些數據。在 MVC 中,視圖保留對模型的引用並運行其自己的邏輯來選擇所需數據,然後將其添加到 UI 元素。有了這個邏輯,視圖不像其在進行測試時那樣被動了。此外,視圖在某種程度上依賴基礎 UI 平臺。
在 MVP 中,表示器實際上是最終用戶和應用程序之間的中介。表示器可以呈現視圖並與模型交互,因此,大部分表示邏輯位於表示器中。由於表示器只是一個普通類,不包含任何 UI,因此從本質上來說,它是一個可測試性更高的類。您可以在 2006 年 8 月出版的《MSDN 雜誌》中的“設計模式”專欄中看到如何在 ASP.NET 中實際實施 MVP 模式。MVP 由 Microsoft Web 客戶端軟件工廠提供本機支持,後者是一個與 ASP.NET 相關的應用程序塊的集合。MSDN 中提供了 MVP 快速入門
MVP 是一個通用的 UI 模式,與 Model2 不同之處在於它並不專用於 Web,但 Model2 (ASP.NET MVC Framework) 和 MVP 基本上是相同的。有趣的是,這兩個模式最初都不是設計爲通用模式。
從技術層面來講,Model2 和 MVP 之間只有一點不同:控制器(在 MVP 中稱爲表示器)和視圖之間的約定。Model2 中對約定的定義欠嚴謹,而 MVP 中的定義比較正規。
在 MVP 中,視圖實現一個界面,表示器僅使用該界面上的成員與視圖進行交互。因此,例如表示器使用界面中的方法和 getter 讀取視圖中的輸入數據,並使用界面中的方法和/或 setter 設置視圖的新值。在 Model2 中,則使用強類型化的容器。
通過使用 MVP,表示邏輯可以獨立於 UI 平臺存在,這樣在不同的平臺間重複使用相同的表示器會更容易。此外,相同的表示器可以處理同一應用程序中的不同的視圖,因此可啓用軟件即服務 (SaaS) 方案。最後,利用 MVP,您還獲得了一個組件(表示器),其中可能存儲了一些邏輯可在頁面間導航。是在內部實現邏輯還是使用 Windows Workflow Foundation (WF) 組件取決於您自己的意願。

頁面控制器模式
MVC、Model2 和 MVP 是 ASP.NET 運行時設計的外部模式。ASP.NET 的 Web 窗體編程模型基於另一種設計模式,即頁面控制器模式。頁面控制器模式要求創建核心對象(動態創建的從代碼隱藏類繼承的類),該核心對象可以處理所有指向特定網頁的 HTTP 請求(請參見圖 7)。
圖 7 頁面控制器結構
如果自定義此模式,您可能會因爲在頁面間重複使用邏輯(包括導航邏輯)而受益。只需通過創建 Page 類的層次結構然後將導航邏輯和表示邏輯合併到層次結構較高的類中,以使該邏輯可供派生類使用,即可自定義該模式。自定義頁面控制器是一個有效的方式,可以提高表示邏輯和導航邏輯的可重用性,而無需切換到一種全新的模式。
應用 MVP 實際上意味着通過實現 Page 類上的接口並使用一個單獨的組件(表示器)處理用戶操作,以其他方式來設計頁面的代碼隱藏類。不會對運行時環境進行任何更改,因爲請求將以常規方式路由至代碼隱藏類。
創建 ASP.NET MVC Framework 項目意味着對運行時環境進行更改以啓用前端控制器(URL 路由模塊),進而根據控制器上的操作處理請求。這兩個選項都會對應用程序的開發產生影響。
第一個要確定的問題是是否需要視圖狀態和服務器控件。在某些情況下,您可能不想使用這些控件。例如,如果沒有服務器控件,使用 CSS 對 UI 進行樣式設計會更簡單。在當前情況下,使用包含服務器控件的 AJAX 比使用 ASP.NET MVC Framework 方案更簡單。但如果沒有豐富的服務器控件,很難構建包含大量數據輸入或基於表的複雜視圖的應用程序。因此,主要是找到一個平衡點。關鍵問題是您是否需要服務器控件和視圖狀態。這個問題沒有明確的答案。
如果您決定最好還是堅持使用 Web 窗體,但仍想偶爾使用 SoC,則可以選擇使用 MVP。MVP 是一個非常重要的 UI 模式,在相對簡單的應用程序中實施該模式可能有些浪費。另一方面,在企業級應用程序使用 MVP 效果非常好,因爲此時您真正需要在多個平臺之間和 SaaS 方案中重複使用儘可能多的表示邏輯。
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章