基于MVVM模式開(kāi)發(fā)Silverlight 3應(yīng)用(理論篇)
原創(chuàng)【51CTO精選譯文】在本系列文章中,我們將通過(guò)一個(gè)簡(jiǎn)單的Silverlight 3.0實(shí)例向您展示如何通過(guò)使用當(dāng)前成熟的應(yīng)用程序設(shè)計(jì)模式,即“模型—視圖—視圖模型” 模式,來(lái)實(shí)現(xiàn)用戶(hù)界面層與其相關(guān)數(shù)據(jù)層的分離設(shè)計(jì)。本文原文講述內(nèi)容針對(duì)Silverlight 2.0,不過(guò)據(jù)譯者觀察,Silverlight 2和Silverlight 3在架構(gòu)方面沒(méi)有太大變化,此文內(nèi)容可以通用。
一、引言
當(dāng)前,Silverlight的正式版本為3.0,基于此技術(shù)的應(yīng)用程序數(shù)量正在急劇增長(zhǎng)。但是,到目前為止,Silverlight 3.0模板所支持的基本結(jié)構(gòu)卻意味著用戶(hù)界面(UI)與其所需要的任何數(shù)據(jù)間是緊密集成的關(guān)系。雖然這種緊密集成的技術(shù)對(duì)于學(xué)習(xí)Silverlight本身來(lái)說(shuō)是有益的,但是,當(dāng)使用之來(lái)開(kāi)發(fā)真實(shí)的應(yīng)用程序時(shí)卻會(huì)為測(cè)試、重構(gòu)和維護(hù)等工作帶來(lái)巨大的困難。
二、緊耦合設(shè)計(jì)帶來(lái)的問(wèn)題
在設(shè)計(jì)Silverlight應(yīng)用程序時(shí),我們所關(guān)心的核心問(wèn)題是緊密耦合問(wèn)題。造成這種緊密耦合的原因是:開(kāi)發(fā)過(guò)程中,我們很容易把應(yīng)用程序的各個(gè)層混合在一起。當(dāng)一個(gè)層中擁有另一個(gè)層中所需要的大量信息時(shí),說(shuō)明你的應(yīng)用程序正處于緊密耦合狀態(tài)。我們不妨來(lái)考慮一個(gè)簡(jiǎn)單的Silverlight數(shù)據(jù)輸入應(yīng)用程序,假定此程序允許你查詢(xún)某個(gè)城市的待售房屋信息。在一個(gè)緊密耦合的應(yīng)用程序中,您可能會(huì)在用戶(hù)界面中的一個(gè)按鈕的Click事件處理程序中定義執(zhí)行搜索的查詢(xún)操作。于是,當(dāng)規(guī)則改變或搜索語(yǔ)義發(fā)生變化時(shí),無(wú)論是數(shù)據(jù)層還是用戶(hù)界面層都必須進(jìn)行相應(yīng)的更新。
這種情況勢(shì)必導(dǎo)致代碼質(zhì)量和編碼復(fù)雜性的問(wèn)題。每當(dāng)數(shù)據(jù)層改變時(shí),你必須進(jìn)行同步更新并測(cè)試應(yīng)用程序,以便確保所做的更改沒(méi)有與發(fā)生的變化相違背。當(dāng)一切都緊密地綁在一起時(shí),在一個(gè)應(yīng)用程序某一部分中的任何變化都可能會(huì)導(dǎo)致在代碼的其他部位發(fā)生相應(yīng)的變化。當(dāng)你使用Silverlight開(kāi)發(fā)簡(jiǎn)單的程序,例如一個(gè)電影播放器或菜單組件,緊密耦合的應(yīng)用程序組件不太可能造成大的問(wèn)題。但是,隨著項(xiàng)目尺寸的不斷增大,你會(huì)感覺(jué)到麻煩越來(lái)越多。
另一個(gè)問(wèn)題是單元測(cè)試的問(wèn)題。當(dāng)一個(gè)應(yīng)用程序是緊密耦合型的,你只能進(jìn)行應(yīng)用程序的功能(或用戶(hù)界面)測(cè)試。同樣,這對(duì)于一個(gè)小項(xiàng)目不是什么問(wèn)題,但是隨著項(xiàng)目規(guī)模和復(fù)雜性的不斷增長(zhǎng),能夠分層測(cè)試應(yīng)用就變得非常重要。請(qǐng)記住,單元測(cè)試并不只是確保當(dāng)在一個(gè)系統(tǒng)中使用它時(shí)此單元能夠工作,而是需要確保它能夠在一個(gè)系統(tǒng)中繼續(xù)不斷地使用。對(duì)系統(tǒng)各個(gè)局部進(jìn)行單元測(cè)試可以保證,隨著系統(tǒng)的變化,在這個(gè)過(guò)程中會(huì)更早期地發(fā)現(xiàn)問(wèn)題,而不是和僅使用功能測(cè)試那樣在最后才發(fā)現(xiàn)問(wèn)題。因此,回歸測(cè)試(例如,針對(duì)一個(gè)系統(tǒng)的每一個(gè)版本都進(jìn)行單元測(cè)試)就變得至關(guān)重要—它可以確保系統(tǒng)中新增加的小變化不至于造成一系列的錯(cuò)誤。
在程序開(kāi)發(fā)過(guò)程中,定義不同的層可能會(huì)對(duì)一些程序員造成巨大的壓力。但是,事實(shí)是:無(wú)論你是否考慮到基于分層思想構(gòu)建程序,你都是工作在一個(gè)N層平臺(tái)上,而且你的應(yīng)用程序也都將分層工作。因此,如果設(shè)計(jì)之初缺乏正確的計(jì)劃,你的應(yīng)用程序最終將要么成為一個(gè)緊耦合的系統(tǒng),要么充滿(mǎn)了大量的硬編碼,從而為以后的應(yīng)用程序維護(hù)帶來(lái)巨大的難題。
人們很容易以為建立一個(gè)有獨(dú)立的層次的應(yīng)用程序一定需要大量的基礎(chǔ)設(shè)施才能使其良好地工作。但事實(shí)上,實(shí)現(xiàn)層之間的簡(jiǎn)單分離卻是相當(dāng)直接的事情。當(dāng)然,你還可以通過(guò)使用控制反轉(zhuǎn)等技術(shù)設(shè)計(jì)更復(fù)雜的應(yīng)用程序分層,但這是要解決另外一些不同的問(wèn)題—在本文中并不予以討論。
三、以分層模式設(shè)計(jì)Silverlight應(yīng)用程序
Silverlight程序并不要求你發(fā)明什么新東西,以便幫助你決定如何實(shí)現(xiàn)一個(gè)應(yīng)用程序的分層設(shè)計(jì)。事實(shí)上,已經(jīng)有一些眾所周知的模式可以供你使用。人們很快會(huì)想到的一種模式是MVC(模型-視圖-控制器)模式。在MVC模式中,模型是數(shù)據(jù),視圖是用戶(hù)接口,控制器是位于視圖、模型和用戶(hù)輸入之間的編程接口。但是,這種模式在類(lèi)似WPF或Silverlight應(yīng)用程序中實(shí)現(xiàn)聲明式用戶(hù)接口編程時(shí)效率并不高,因?yàn)檫@些技術(shù)所使用的XAML可能會(huì)在輸入與視圖之間定義某種接口(因?yàn)閿?shù)據(jù)綁定、觸發(fā)器和狀態(tài)都可以以聲明方式存在于XAML代碼中)。
MVP(模型—視圖—提供器)是另一個(gè)實(shí)現(xiàn)應(yīng)用程序分層設(shè)計(jì)時(shí)常見(jiàn)的模式。在MVP設(shè)計(jì)模式中,提供器負(fù)責(zé)制定和管理視圖的狀態(tài)。像MVC模式一樣,MVP模式也不太適合目前的Silverlight模型,因?yàn)閄AML代碼中可能包含聲明式的數(shù)據(jù)綁定,觸發(fā)器和狀態(tài)管理。那么,這種模式帶來(lái)我們?cè)鯓拥膯⑹灸兀?/p>
另一方面,值得慶幸的是,WPF社團(tuán)已經(jīng)推出一種稱(chēng)為MVVM(模型-視圖-視圖模型)的模式。這種模式是對(duì)MVC與MVP模式的改進(jìn)。在該模式中,視圖模型部分為視圖部分提供了一個(gè)數(shù)據(jù)模型和行為,但允許視圖部分以聲明方式綁定到視圖模型上。于是,視圖部分變成了一種XAML和C#的混合體(就像Silverlight控件一樣),而模型部分描述了提供給應(yīng)用程序的數(shù)據(jù)部分,由視圖模型準(zhǔn)備模型部分,以便把它綁定到視圖部分。
在MVVM模式中,模型部分特別重要,因?yàn)樗庋b了對(duì)底層數(shù)據(jù)的訪(fǎng)問(wèn)—無(wú)論訪(fǎng)問(wèn)方式是通過(guò)一組Web服務(wù),一個(gè)ADO.NET數(shù)據(jù)服務(wù),或是一些其他形式的數(shù)據(jù)檢索方案。該模型部分與視圖模式是相分離的,從而使視圖的數(shù)據(jù)(即視圖模型部分)能夠獨(dú)立于實(shí)際數(shù)據(jù)進(jìn)行測(cè)試。圖1展示了一個(gè)MVVM模式的例子。
四、構(gòu)建示例方案
#T#在簡(jiǎn)單地總結(jié)了流行的應(yīng)用開(kāi)發(fā)模式之后,為了幫助您更具體地理解MVVM模式的實(shí)現(xiàn)方案,我們來(lái)分析一個(gè)簡(jiǎn)單的Silverlight 3應(yīng)用示例。當(dāng)然,這個(gè)例子未必反映了實(shí)際的情形,僅用于說(shuō)明這一模式。
這個(gè)例子由五個(gè)不同的項(xiàng)目組成,共同存在于一個(gè)Visual Studio解決方案中。(盡管你不需要針對(duì)每一個(gè)單獨(dú)的項(xiàng)目創(chuàng)建一個(gè)單獨(dú)的層,但是這樣做卻往往是一個(gè)不錯(cuò)的選擇。)請(qǐng)注意,這個(gè)例子把整個(gè)解決方案進(jìn)一步分離到兩個(gè)文件夾中,即Client文件夾和Server文件夾。
其中,在Server文件夾中有兩個(gè)項(xiàng)目:一個(gè)ASP.NET Web應(yīng)用程序(MVVMExample),它將負(fù)責(zé)承載我們的Silverlight項(xiàng)目和有關(guān)服務(wù);另一個(gè)是一個(gè).NET類(lèi)庫(kù)項(xiàng)目,它包含了數(shù)據(jù)模型部分。
在Client文件夾中有三個(gè)項(xiàng)目:一個(gè)Silverlight項(xiàng)目(MVVM.Client),用于實(shí)現(xiàn)我們的應(yīng)用程序的主用戶(hù)界面;一個(gè)Silverlight客戶(hù)端庫(kù)(MVVM.Client.Data),其中包含了模型部分和視圖模型部分,還有服務(wù)引用;最后一個(gè)是Silverlight項(xiàng)目(MVVM.Client.Tests),其中包含了單元測(cè)試內(nèi)容。從圖2中你可以觀察到這種拆開(kāi)來(lái)的項(xiàng)目布局。
在本例中,在服務(wù)器端構(gòu)建上,我使用的技術(shù)有:ASP.NET,Entity Framework(實(shí)體框架)和一個(gè)ADO.NET數(shù)據(jù)服務(wù)。從本質(zhì)上看,我在服務(wù)器端創(chuàng)建了一個(gè)簡(jiǎn)單的數(shù)據(jù)模型,而且選擇基于REST的服務(wù)方式來(lái)對(duì)外提供這種數(shù)據(jù)模型的使用。篇幅所限,有關(guān)ADO.NET數(shù)據(jù)服務(wù)的細(xì)節(jié)討論,在此略過(guò)。
五、小結(jié)
在本篇中,我們首先介紹了在設(shè)計(jì)Silverlight應(yīng)用程序時(shí)最令我們所關(guān)心的緊密耦合問(wèn)題。然后,介紹了幾種流行的軟件開(kāi)發(fā)模式,并最終確定MVVM模式最適合于目前的Silverlight 3應(yīng)用程序開(kāi)發(fā)。最后,簡(jiǎn)單給出了我們要開(kāi)發(fā)的案例的大致架構(gòu)布局。
原文:Model-View-ViewModel In Silverlight 2 Apps 作者:Shawn Wildermuth
























