王念橋
摘要: 模型-視圖-控制器 (MVC) 模式是一個框架級的設計模式,該模式將軟件設計中的關注點分離開來,從而使程序更有彈性。隨著軟硬件的發展,基于MVC模式演化出了一些相關模式。模型-視圖-表示器 (MVP) 模式就是由MVC演變而來。文章將首先介紹了可能的MVP模式的實現方法,然后討論了該模式的應用,以及所帶來的益處。
關鍵詞: 模式; MVC; MVP; 軟件架構
中圖分類號:TP302.1文獻標識碼:A文章編號:1006-8228(2012)04-37-02
Improving software architecture with MVP mode
Wang Nianqiao
(Wuhan technical college, department of electronic & information,Hubei, Wuhan 430074, China)
Abstract: Applying the Model-View-Controller (MVC) mode shows that designing applications with different concerns makes programs more flexible. Several variations of it appeared over the years, and one of those is the Model-View-Presenter (MVP). In this article, one possible implementation of the MVP mode, its application and its benefits will be introduced.
Key words: mode; MVC; MVP; software architecture
1 MVP 概覽
MVP演變自MVC[1],通過表示器將視圖與模型巧妙地分開。在該模式中,視圖通常由表示器初始化,它呈現用戶界面(UI)并接受用戶所發出命令,但不對用戶的輸入作任何邏輯處理,而僅僅是將用戶輸入轉發給表示器。通常每一個視圖對應一個表示器。表示器包含大多數表示邏輯,用以處理視圖,與模型交互以獲取或更新數據等。模型描述了系統的處理邏輯,模型對于表示器和視圖一無所知。
[View][Presenter][Model]
圖1MVP 模式
MVP 中表示器通過接口(當然也可能是抽象基類)與視圖交互[2,3]。采用這種方案可以使表示器自身成為一個可重用性和可測試性均很高的類。首先,表示邏輯獨立于所使用的UI技術,因此,可在Windows和Web表示層中重用同一表示器。其次,針對某一接口為表示器編碼,該表示器可以與實現該接口的任何對象交互,而實現該接口的可能是 Windows窗體對象、ASP.NET頁面對象或者WPF窗口對象,這意味著只要視圖接口不變,視圖的任何更新都不會影響到表示器。再者,同一表示器可以處理同一應用程序的不同視圖。比如,在軟件即服務 (SaaS)中,應用程序托管在 Web 服務器上,并作為服務提供給每一個要求使用自定義 UI 的客戶。最后,如果將應用邏輯混合于UI代碼中,由于應用程序中的UI代碼非常難以自動測試,從而導致整個應用的難以測試。因此,從UI分離出視圖接口,將UI中的邏輯從視圖中移除后,通過模仿視圖對象,可以方便地測試表示器。
當然上述所有優點不一定存在于所有情況,使用單一UI技術的應用就無法體現重用表示器的好處,但是無論如何,能夠提高可測試性我們的研究就是非常值得的。
2 MVP實踐
2.1 視圖接口
同MVC一樣,MVP也是軟件框架級的設計架構[4]。實現 MVP 模式時,要為每個視圖定義抽象接口。接口標識視圖支持的數據模型。無論哪種平臺,每個邏輯上等效的視圖都具有相同的接口。表示器通過此接口與視圖交互。
視圖抽象包含視圖可識別和可處理的模型,并且可以使用一些有用的特殊方法和事件來擴展模型,幫助表示器與視圖之間實現流暢交互。下面是一個顯示新聞的視圖接口示例,視圖上包含一個新聞列表,選中其中一項將顯示具體的新聞內容。
public interface INewsDetailsView {
int NewsId { set; }
string Title{ set; }
…
void AddNews(int newsId,string title,string authorName,datetime publishedDate,string content);
}
表示器與UI之間的任何交互都必須通過視圖接口進行。 用戶的任何命令都必須轉發到表示器,并由其進行處理。如果表示器需要查詢視圖中的某些數據,或者將數據向下傳遞到視圖,接口中應該有方法負責執行該操作。
2.2 表示器
視圖中的控件將捕獲任何用戶操作并觸發視圖中的事件,例如按鈕單擊或索引選擇更改事件。視圖包含簡單的事件處理程序,向負責視圖的表示器分派調用。
表示器類通常通過其構造函數接收對視圖的引用。視圖保留對表示器的引用,表示器保留對視圖接口的引用,表示器不依賴于具體的視圖對象。下面是一個顯示新聞的表示器示例。
public class NewsDetailsPresenter {
private readonly INewsDetailsView view;
public NewsDetailsPresenter(INewsDetailsView view) {
this.view = view;
…
}
public void Initialize() {
…
}
public void ShowNewsDetails() {
…
}
…
}
構造函數接收并保存對視圖的引用,使用約定所表示的公共接口初始化視圖。表示器類還包含大量方法,執行這些方法可響應來自 UI 的任何請求。任何單擊或用戶操作都與表示器類的方法綁定:
private void OnSelectedIndexChanged(object sender,EventArgs e){
presenter.ShowNewsDetails();
}
表示器使用視圖引用訪問輸入值,并按同樣方式更新 UI。
2.3 實現視圖接口
視圖接口使用某種UI技術的類實現。視圖可能的類有 ASP.NET中的頁面、Windows窗體中的窗體、WPF中的窗口和 Silverlight中的用戶控件。首次加載視圖時,它會創建其表示器類的一個實例,并在內部將其保存為一個私有成員。
public partial class NewsDetailsView:Page,INewsDetailsView{
private NewsDetailsPresenter presenter;
protected void Page_Load(object sender,EventArgs e){
presenter = new NewsDetailsPresenter(this);
if(!IsPostback)
presenter. Initialize();
}
public int NewsId {
set { newsId_Label.Text = value.ToString(); }
}
public string Title {
set { newsTitle_Label.Text = value; }
}
...
}
視圖中的屬性是以可視控件上某些屬性的包裝形式實現的。例如,Title 屬性是Label控件的Text屬性的包裝。重要的是,接口為表示器屏蔽了給定平臺的UI詳細信息。對于所創建的用于與INewsDetailsView接口交互的表示器類,可以處理實現該接口的任何對象,而無須涉及底層控件的編程接口的詳細信息。
MVP模式被分成兩種單獨模式,Supervising Controller 和Passive View[5]。Passive View中視圖對模型一無所知;而Supervising Controller將會向視圖中添加某些表示邏輯,比如使用數據綁定。實踐中,很多時候都是這兩種模式的混合體。
2.4 應用程序導航
表示器也負責在應用程序中導航。比如在同一個視圖下,為響應用戶命令打開一個對話框,可通過視圖接口的成員(大多數是布爾值成員)來控制。若需要將控件傳送到其他視圖(和表示器),則可以創建一個表示應用程序控制器的靜態類,用以確定下一個視圖,其作用就是一個導航的中心控制臺。
復雜的導航可以通過工作流的方式來完成,最簡單的也可能只要一個switch語句。工作流可以是任意形式,可以與實際工作流一樣復雜,當然也可以與一個if語句序列那樣簡單。 在應用程序控制器中可按靜態方式對工作流邏輯進行編碼,也可以從外部可插入組件導入工作流邏輯。
應用程序控制器中的實際導航邏輯將使用特定于平臺的解決方案來切換到不同視圖。對于Windows窗體,它使用特定方法打開和顯示窗體;在ASP.NET中,它使用Response對象的Redirect方法。
3 其他變體
ASP.NET MVC基于MVC模式風格,與 MVP具有一些共同的特征。 MVC 中的控制器是視圖與后端之間的調節器。控制器不保留對視圖的引用,但會初始化模型對象,并使用中間組件(視圖引擎)的服務將其傳遞到視圖。
WPF與Silverlight應用程序可能更適合模型視圖-視圖模型(MVVM )。MVVM是MVP的變體,將視圖模型包含到表示器類中,表示器類公開視圖將進行讀寫操作的公共成員。這是通過雙向數據綁定實現的,雙向綁定由框架提供內在支持。
在 MVVM 中,視圖與表示器類(視圖模型)的屬性被數據綁定,用戶執行任何操作都會更新表示器中的這些屬性,用戶發出的任何請求(WPF 中的命令)都被表示器類的方法進行處理。表示器方法計算出的任何結果都存儲在視圖模型中,并通過數據綁定提供給視圖。
4 結束語
MVP模式分離了應用程序的關注點,增強了代碼的可測試性,但增加了應用程序中類的數量。對于小型程序而言,這可能會提高軟件開發的成本。與此同時,大型應用程序更易于承擔這些成本。因此,MVP 并不是對于開發任何應用程序都適用。無論如何,采用MVP后,根據表示視圖的約定,設計人員和開發人員可以并行工作,這在任何開發中都是一個值得采用的實踐方式。
參考文獻:
[1] Martin Fowler. Patterns of Enterprise Application Architecture[M].人民郵電出版社,2009.
[2] Robert C Martin, Micah Martin. 敏捷軟件開發-原則、模式與實踐(C#版)[M].人民郵電出版社,2008.
[3] Dino Esposito, Andrea Saltarello. Microsfot.Net Architecting Applications for the Enterprise[M].人民郵電出版社,2009.
[4] 溫昱. 一線架構師實踐指南[M].電子工業出版社,2009.
[5] Peter Eeles, Peter Cripps.架構實戰:軟件架構設計的過程[M]. 機械工業出版社,2010.