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