av网站免费线看精品_国产做a爱视频免费不_深爱激情网开心五月天_伊人五月天在线视频网

 
面向?qū)ο蟮膽?yīng)用服務(wù)層設(shè)計(jì)
發(fā)布時(shí)間:2005-02-02   瀏覽次數(shù):1235242
作者:理想轉(zhuǎn)貼自:理想帝國(guó) 前言   N層的應(yīng)用軟件系統(tǒng),由于其眾多的優(yōu)點(diǎn),已經(jīng)成為典型的軟件系統(tǒng)架構(gòu),也已經(jīng)為廣大開(kāi)發(fā)人員所熟知。在一個(gè)典型的三層應(yīng)用軟件系統(tǒng)中,應(yīng)用系統(tǒng)通常被劃分成以下三個(gè)層次:數(shù)據(jù)庫(kù)層、應(yīng)用服務(wù)層和用戶界面層。如下圖所示:   其中,應(yīng)用服務(wù)層集中了系統(tǒng)的業(yè)務(wù)邏輯的處理,因此,可以說(shuō)是應(yīng)用軟件系統(tǒng)中的核心部分。軟件系統(tǒng)的健壯性、靈活性、可重用性、可升級(jí)性和可維護(hù)性,在很大程度上取決于應(yīng)用服務(wù)層的設(shè)計(jì)。因此,如何構(gòu)建一個(gè)良好架構(gòu)的應(yīng)用服務(wù)層,是應(yīng)用軟件開(kāi)發(fā)者需要著重解決的問(wèn)題。   為了使應(yīng)用服務(wù)層的設(shè)計(jì)達(dá)到的效果,我們通常還需要對(duì)應(yīng)用服務(wù)層作進(jìn)一步的職能分析和層次細(xì)分。很多開(kāi)發(fā)者在構(gòu)建應(yīng)用服務(wù)層的時(shí)候,把數(shù)據(jù)庫(kù)操縱、業(yè)務(wù)邏輯處理甚至界面顯示夾雜在一起,或者,把業(yè)務(wù)邏輯處理等同于數(shù)據(jù)庫(kù)操縱,等等,這些,都是有缺陷的做法。本文,在這個(gè)方面進(jìn)行設(shè)計(jì)時(shí)可采用的方案進(jìn)行一些探討。   為了使討論更具有針對(duì)性,本文會(huì)討論一些比較流行的系統(tǒng)架構(gòu),例如J2EE架構(gòu),以及JDO。在微軟的.Net平臺(tái)上,將以Websharp中間件為例。Websharp中間件是筆者開(kāi)發(fā)的一個(gè)構(gòu)建在微軟.Net平臺(tái)之上的一個(gè)中間件系統(tǒng),也是實(shí)現(xiàn)文章所述的系統(tǒng)架構(gòu)的支撐系統(tǒng)。選用這些架構(gòu)做例子,也是因?yàn)?Net出現(xiàn)的時(shí)間比較短,目前在這個(gè)平臺(tái)上沒(méi)有成熟統(tǒng)一的架構(gòu),而J2EE是目前最成熟的構(gòu)建企業(yè)應(yīng)用的平臺(tái)。   自本人的《利用.Net框架開(kāi)發(fā)應(yīng)用系統(tǒng)》和《實(shí)戰(zhàn)揭秘:開(kāi)發(fā).Net平臺(tái)應(yīng)用系統(tǒng)框架》兩篇文章發(fā)表以來(lái),收到很多反饋和來(lái)信,提出了很多問(wèn)題。因?yàn)闀r(shí)間的關(guān)系,不能一一回復(fù),因此,也借本文給大家一些解答。需要說(shuō)明的是,原來(lái)的Jobsinfo現(xiàn)在已經(jīng)做了升級(jí),名稱變更為Websharp。   設(shè)計(jì)的原則和評(píng)判標(biāo)準(zhǔn)   同軟件工程的原則一樣,應(yīng)用服務(wù)層的設(shè)計(jì),必須遵循的最重要的原則是高內(nèi)聚和低耦合。軟件分層的本來(lái)目的,是提高軟件的可維護(hù)性和可重用性,而高內(nèi)聚和低耦合正是達(dá)成這一目標(biāo)必須遵循的原則。盡量降低系統(tǒng)各個(gè)部分之間的耦合度,是應(yīng)用服務(wù)層設(shè)計(jì)中需要重點(diǎn)考慮的問(wèn)題。   內(nèi)聚和耦合,包含了橫向和縱向的關(guān)系。功能內(nèi)聚和數(shù)據(jù)耦合,是我們需要達(dá)成的目標(biāo)。橫向的內(nèi)聚和耦合,通常體現(xiàn)在系統(tǒng)的各個(gè)模塊、類之間的關(guān)系,而縱向的耦合,體現(xiàn)在系統(tǒng)的各個(gè)層次之間的關(guān)系。   系統(tǒng)的框架,通常包含了一系列規(guī)范、約定和支撐類庫(kù)、服務(wù)。   對(duì)于如何判斷一個(gè)軟件的系統(tǒng)框架的優(yōu)劣,筆者認(rèn)為,可以從以下幾個(gè)方面來(lái)評(píng)判:   ◆ 系統(tǒng)的內(nèi)聚和耦合度   這是保證一個(gè)系統(tǒng)的架構(gòu)是否符合軟件工程原則的首要標(biāo)準(zhǔn)。   ◆ 層次的清晰和簡(jiǎn)潔性   系統(tǒng)每個(gè)部分完成功能和目標(biāo)必須是明確的,同樣的功能,應(yīng)該只在一個(gè)地方實(shí)現(xiàn)。如果某個(gè)功能可以在系統(tǒng)不同的地方實(shí)現(xiàn),那么,將會(huì)給后來(lái)的開(kāi)發(fā)和維護(hù)帶來(lái)問(wèn)題。   系統(tǒng)應(yīng)該簡(jiǎn)單明了,過(guò)于復(fù)雜的系統(tǒng)架構(gòu),會(huì)帶來(lái)不必要的成本和維護(hù)難度。在盡可能的情況下,一個(gè)部分應(yīng)該完成一個(gè)單獨(dú)并且完整的功能。   ◆ 易于實(shí)現(xiàn)性   如果系統(tǒng)架構(gòu)的實(shí)現(xiàn)非常困難,甚至超出團(tuán)隊(duì)現(xiàn)有的技術(shù)能力,那么,團(tuán)隊(duì)不得不花很多的精力用于架構(gòu)的開(kāi)發(fā),這對(duì)于整個(gè)項(xiàng)目來(lái)說(shuō),可能會(huì)得不償失。簡(jiǎn)單是美。   ◆ 可升級(jí)和可擴(kuò)充性   一個(gè)系統(tǒng)框架,受設(shè)計(jì)時(shí)技術(shù)條件的限制,或者設(shè)計(jì)者本人對(duì)系統(tǒng)認(rèn)識(shí)的局限,可能不會(huì)考慮到今后所有的變化。但是,系統(tǒng)必須為將來(lái)可能的變化做好準(zhǔn)備,能夠在今后,在目前已有的基礎(chǔ)上進(jìn)行演進(jìn),但不會(huì)影響原有的應(yīng)用。接口技術(shù),是在這個(gè)方面普遍應(yīng)用的技巧。   ◆ 是否有利于團(tuán)隊(duì)合作開(kāi)發(fā)   一個(gè)好的系統(tǒng)架構(gòu),不僅僅只是從技術(shù)的角度來(lái)看,而且,它還應(yīng)該適用于團(tuán)隊(duì)開(kāi)發(fā)模型,可以方便一個(gè)開(kāi)發(fā)團(tuán)隊(duì)中各個(gè)不同角色的互相協(xié)作。例如,將Web頁(yè)面和業(yè)務(wù)邏輯組件分開(kāi),可是使頁(yè)面設(shè)計(jì)人員和程序員的工作分開(kāi)來(lái)同步進(jìn)行而不會(huì)互相影響。   ◆ 性能   性能對(duì)于軟件系統(tǒng)來(lái)說(shuō)是很重要的,但是,有的時(shí)候,為了能讓系統(tǒng)得到更大的靈活性,可能不得不在性能和其他方面取得平衡。另外一個(gè)方面,由于硬件技術(shù)的飛速發(fā)展和價(jià)格的下降,性能的問(wèn)題往往可以通過(guò)使用使用更好的硬件來(lái)獲得提升。   應(yīng)用服務(wù)層的內(nèi)容   應(yīng)用服務(wù)層,通常也被稱為業(yè)務(wù)邏輯層,因?yàn)檫@一層,是應(yīng)用軟件系統(tǒng)業(yè)務(wù)邏輯處理集中的部分。然而,我將這一層稱為應(yīng)用服務(wù)層,而不稱業(yè)務(wù)邏輯層,因?yàn)椋@一層需要處理的不僅僅是業(yè)務(wù)邏輯,還包含了其他方面的內(nèi)容。   從完整的角度來(lái)說(shuō),應(yīng)用服務(wù)層需要處理以下內(nèi)容:   ◆ 數(shù)據(jù)的表示方式   數(shù)據(jù),是軟件處理的對(duì)象。從某種程度上來(lái)說(shuō),"軟件,是數(shù)據(jù)結(jié)構(gòu)加算法"的說(shuō)法,是有一定意義的。在面向?qū)ο蟮南到y(tǒng)中,數(shù)據(jù)是用類來(lái)表示的,代表了現(xiàn)實(shí)世界實(shí)體對(duì)象在軟件系統(tǒng)中的抽象?紤]所謂的MVC模式,這個(gè)部分的類屬于M--實(shí)體類的范疇。由于應(yīng)用軟件通常會(huì)使用數(shù)據(jù)庫(kù),數(shù)據(jù)庫(kù)中的數(shù)據(jù),可以看成是對(duì)象的持久化保存。由于數(shù)據(jù)庫(kù)一般是關(guān)系型的,因此,這個(gè)部分,還需要考慮類(對(duì)象)同關(guān)系型數(shù)據(jù)的映射,即通常所說(shuō)的O-R MAP問(wèn)題。   ◆ 數(shù)據(jù)的存取方式   如同上述所說(shuō),軟件系統(tǒng)處理的實(shí)體對(duì)象數(shù)據(jù)需要持久化保存數(shù)據(jù)庫(kù)中,因此,我們必須處理系統(tǒng)同數(shù)據(jù)庫(kù)的交互,以及數(shù)據(jù)的存取和轉(zhuǎn)換方式的問(wèn)題。   ◆ 業(yè)務(wù)邏輯的組織方式   在面向?qū)ο蟮南到y(tǒng)中,業(yè)務(wù)邏輯表現(xiàn)為對(duì)象之間的交互。有了上述的實(shí)體對(duì)象,以及對(duì)象的保存策略,可以將這些對(duì)象組合起來(lái),編寫(xiě)我們的業(yè)務(wù)邏輯處理程序。在業(yè)務(wù)邏輯的處理中,必須保證處理的正確性和完整性,這將會(huì)涉及到事務(wù)處理。通常,我們也會(huì)把業(yè)務(wù)邏輯封裝成組件的形式,以得到的可重用性。   ◆ 業(yè)務(wù)服務(wù)的提供方式   在我們完成系統(tǒng)的功能后,如何向客戶提供服務(wù),是我們需要考慮的問(wèn)題。這里的客戶,不僅僅是指軟件的使用者,也包括調(diào)用的界面、其他程序等。例如,在一個(gè)基于Web的ASP.Net或JSP系統(tǒng)中,業(yè)務(wù)邏輯功能的客戶便是這些ASP.Net頁(yè)面或JSP頁(yè)面。業(yè)務(wù)邏輯組件應(yīng)該通過(guò)什么方式,直接的,或間接的,向這些客戶提供服務(wù),是這一層需要完成的任務(wù)。   ◆ 層的部署和層間交互   對(duì)于一個(gè)多層的應(yīng)用軟件系統(tǒng)來(lái)說(shuō),尤其是大型的應(yīng)用軟件系統(tǒng),通常需要把不同的部分部署在不同的邏輯或物理設(shè)備上。特別是一些基于Web的應(yīng)用軟件系統(tǒng),其部署工作將涉及到Web服務(wù)器、組件服務(wù)器、數(shù)據(jù)庫(kù)服務(wù)器等不同的服務(wù)設(shè)備。在進(jìn)行應(yīng)用軟件架構(gòu)的設(shè)計(jì)的時(shí)候,必須考慮各種不同的部署方案。   綜上所述,一個(gè)完整的基于Web的應(yīng)用軟件系統(tǒng),其架構(gòu)可以用下圖來(lái)表示(Websharp推薦的應(yīng)用軟件系統(tǒng)架構(gòu)):   對(duì)于以上各個(gè)方面來(lái)說(shuō),每個(gè)問(wèn)題都可以有很多種策略和方案,但是,在一個(gè)系統(tǒng)中,應(yīng)該盡可能的統(tǒng)一這些策略和方案。也是說(shuō),在一個(gè)系統(tǒng),或者一個(gè)項(xiàng)目中,應(yīng)該統(tǒng)一每個(gè)解決每個(gè)問(wèn)題所采用的方法。軟件的開(kāi)發(fā)方法是靈活的,可以用不同的方法解決相同的問(wèn)題,這會(huì)誘使開(kāi)發(fā)人員采用他們認(rèn)為能夠表現(xiàn)自己的方法,但是,從整個(gè)系統(tǒng)來(lái)看,這將會(huì)是災(zāi)難性的。我們應(yīng)該盡可能統(tǒng)一,是,采用統(tǒng)一的數(shù)據(jù)表示方式、統(tǒng)一的數(shù)據(jù)存取方式、統(tǒng)一的業(yè)務(wù)邏輯處理方式等。   下面,將這些部分的設(shè)計(jì)策略和可用方案進(jìn)行一些比較詳細(xì)的論述。   數(shù)據(jù)實(shí)體的表示   應(yīng)用軟件系統(tǒng),從本質(zhì)上來(lái)說(shuō),是計(jì)算機(jī)對(duì)現(xiàn)實(shí)世界的模擬。現(xiàn)實(shí)世界中的實(shí)體對(duì)象,在軟件系統(tǒng)中,表現(xiàn)為需要處理的數(shù)據(jù)。在面向?qū)ο蟮南到y(tǒng)中,這是通過(guò)"類"和"對(duì)象"來(lái)表示的。   參考的"MVC"模式,類可以分成實(shí)體類(M)、控制類(C)、和邊界類(V),分別代表了實(shí)體對(duì)象、控制和界面顯示。系統(tǒng)中需要處理的數(shù)據(jù),在面向?qū)ο蟮南到y(tǒng)中,屬于實(shí)體類部分。   在考慮數(shù)據(jù)實(shí)體層的設(shè)計(jì)策略的時(shí)候,需要把握以下要點(diǎn):   ◆ 一致的數(shù)據(jù)表示方式。在一個(gè)系統(tǒng)中,數(shù)據(jù)的表示方式必須盡可能統(tǒng)一,同時(shí),在處理單個(gè)數(shù)據(jù)和多個(gè)數(shù)據(jù)的時(shí)候,處理方式盡可能一致。   ◆ 因?yàn)閿?shù)據(jù)通常是需要存儲(chǔ)到數(shù)據(jù)庫(kù)中,因此,良好的映射方法是必需的。   ◆ 處理好對(duì)象的粒度,即所謂的粗粒度對(duì)象、細(xì)粒度對(duì)象。   一般例子   考慮一個(gè)現(xiàn)實(shí)的例子,一個(gè)倉(cāng)庫(kù)中的產(chǎn)品(Product),在系統(tǒng)中可以使用如下定義: public class Product{public string Name; //名稱 public decimal Price;//價(jià)格 public int Count;//數(shù)量 } 可以按照如下方法使用Product類: Product p=new Product(); //……處理Product   這是一個(gè)包含了三個(gè)屬性的Product類的定義。為了便于說(shuō)明,在這里,我們盡量將問(wèn)題簡(jiǎn)化了。   又例如,一張入庫(kù)單可以使用如下定義: public class Form{public string ID; //入庫(kù)單編號(hào)public DateTime AddTime; //入庫(kù)時(shí)間public FormDetail[] FormDetails; //入庫(kù)單明細(xì)}public class FormDetail{public Product InProduct; //入庫(kù)產(chǎn)品public int Count; //入庫(kù)數(shù)量}   對(duì)于處理單個(gè)對(duì)象,通常采用上述的方法,但是,當(dāng)我們需要處理相同類的一組對(duì)象,也是處理一個(gè)對(duì)象集合的時(shí)候,會(huì)有一些小小的麻煩。   如前所述,我們希望在處理單個(gè)對(duì)象和對(duì)象集合的時(shí)候,處理的方式盡量統(tǒng)一,這對(duì)于軟件開(kāi)發(fā)的意義是很大的。常用的處理對(duì)象集合的方法有:   ◆數(shù)組表示的方法   例如,上面的例子中當(dāng)一張入庫(kù)單包含多條入庫(kù)單明細(xì)的時(shí)候采用的方法。為了靈活性,也可以使用容器來(lái),如Java中的Vector或C#的ArrayList(C#)。只是,在處理對(duì)象的時(shí)候,需要一個(gè)類型轉(zhuǎn)換的操作。這個(gè)問(wèn)題,在支持泛型的語(yǔ)言中不會(huì)存在,如使用C++的標(biāo)準(zhǔn)庫(kù)的容器類。   ◆ObjectCollection方法。這個(gè)方法同上面的方法類似,不同之處在于,為每個(gè)實(shí)體類設(shè)計(jì)一個(gè)Collection類。例如,可以為FormDetail設(shè)計(jì)一個(gè)FormDetailsCollection類(C#): public class FormDetailsCollection: ArrayList{ public void Add(FormDetail detail){base.Add(detail);} public new FormDetail this[int nIndex] { get{ return (FormDetail)base[nIndex];} }}   這么做的好處在于,在操作集合中的對(duì)象時(shí),不必進(jìn)行類型轉(zhuǎn)換的操作。   ◆數(shù)據(jù)集的表示方法。   采用這種方法,通常是直接把從數(shù)據(jù)庫(kù)查詢中獲取的數(shù)據(jù)集(Recordset)作為數(shù)據(jù)處理對(duì)象。這種方法在ASP應(yīng)用程序中是非常常見(jiàn)的做法。這種做法簡(jiǎn)單,初學(xué)者很容易掌握,但是弊病也很多。   EJB的方法   在J2EE體系中,對(duì)實(shí)體對(duì)象的處理的典型方法是Entity Bean。J2EE中使用Entity Bean來(lái)表示數(shù)據(jù),以及封裝數(shù)據(jù)的持久化儲(chǔ)存(同數(shù)據(jù)庫(kù)的交互)。由于Entity Bean比較消耗資源,而且采用的是遠(yuǎn)程調(diào)用的方式來(lái)訪問(wèn),因此,在需要傳遞大量數(shù)據(jù),或者在不同的層次之間傳遞數(shù)據(jù)的時(shí)候,往往還會(huì)采用一些諸如"值對(duì)象"(Value Object)的設(shè)計(jì)模式來(lái)提升性能。關(guān)于J2EE中的設(shè)計(jì)模式的更多內(nèi)容,讀者可以參考《J2EE核心模式》一書(shū)。   JDO的方法   相對(duì)于J2EE這個(gè)昂貴的方法來(lái)說(shuō),JDO提供了一個(gè)相對(duì)"輕量級(jí)"的方案。在JDO中,你可以采用一般的做法,編寫(xiě)實(shí)體類,然后,通過(guò)一些強(qiáng)化器對(duì)這些類進(jìn)行強(qiáng)化,以使其符合JDO的規(guī)范,,你可以通過(guò)PersistenceManager來(lái)實(shí)現(xiàn)對(duì)象的持久化儲(chǔ)存。   無(wú)論是EJB還是JDO,在同數(shù)據(jù)庫(kù)進(jìn)行映射的時(shí)候,都選用了XML配置文件的方式。這是一種靈活的方式。由于XML強(qiáng)大的表達(dá)能力,我們可以很好的用它來(lái)描述代碼中的實(shí)體類和數(shù)據(jù)庫(kù)之間的映射關(guān)系,并且,不用在代碼中進(jìn)行硬編碼,這樣,在情況發(fā)生變化的時(shí)候,有可能只需要修改配置文件,而不用去修改程序的源代碼。關(guān)于EJB和JDO的配置文件的更多的信息,各位可以參考相關(guān)的文檔,這里不再贅述了。   然而,使用XML配置文件的方式并不是的方法,在微軟提供的一些案例中,如Duwamish示例,沒(méi)有采用這種方式。至于開(kāi)發(fā)人員在開(kāi)發(fā)過(guò)程中具體采用哪種方式,是需要根據(jù)具體情況進(jìn)行權(quán)衡和取舍的。   Websharp的方法   Websharp在數(shù)據(jù)的表現(xiàn)上,充分利用了.Net Framework類庫(kù)中DataSet的功能,設(shè)計(jì)了一個(gè)EntityData類。這個(gè)類繼承了DataSet,并增加了一些屬性和方法。同樣的,同數(shù)據(jù)庫(kù)的映射關(guān)系,也是采用XML配置文件的方式。   在實(shí)際的應(yīng)用中,要獲取一個(gè)實(shí)體對(duì)象,可以通過(guò)如下方式取得: EntityData Customer=EntityDataManager. GetEmptyEntity("Customer");   然后,可以通過(guò)如下方式來(lái)訪問(wèn)這個(gè)對(duì)象的屬性: string CustomerID=Customer["CustomerID"]   可以看到,這種方式同傳統(tǒng)的方式有點(diǎn)不同。在這種方式下,數(shù)據(jù)的表現(xiàn)形式只有一個(gè),那是EntityData。其好處是明顯的,不用為每個(gè)實(shí)體都單獨(dú)編寫(xiě)一個(gè)類,能夠大大減少代碼的編寫(xiě)量。其缺點(diǎn)也很明顯,那是不能利用編譯器類型檢測(cè)的功能,如果在調(diào)用對(duì)象的屬性的時(shí)候,寫(xiě)錯(cuò)了屬性的名稱,可能出錯(cuò),但是,這個(gè)問(wèn)題可以通過(guò)工具來(lái)解決。   關(guān)于這個(gè)方面更加詳細(xì)的信息,可以參見(jiàn)拙文:   《利用.Net框架開(kāi)發(fā)應(yīng)用系統(tǒng)》   《實(shí)戰(zhàn)揭秘:開(kāi)發(fā).Net平臺(tái)應(yīng)用系統(tǒng)框架》   數(shù)據(jù)的存取方式   數(shù)據(jù)存取的目的,是持久化保存對(duì)象,以備后來(lái)的使用,如查詢、修改、統(tǒng)計(jì)分析等。存取的對(duì)象,可以是數(shù)據(jù)庫(kù)、普通文件、XML甚至其他任何方式,只要保證數(shù)據(jù)能夠長(zhǎng)久保存,并且,不會(huì)受斷電、系統(tǒng)重起等因素的影響。在這個(gè)部分,最理想的狀況,自然是能夠支持除了數(shù)據(jù)庫(kù)以外的各種類型的存取方式,或者,至少留有接口,能夠比較方便的擴(kuò)充。   因?yàn)閿?shù)據(jù)庫(kù)是最常用,也是最有效的數(shù)據(jù)存儲(chǔ)方法,因此,支持?jǐn)?shù)據(jù)庫(kù)存儲(chǔ)是最首先必須支持的。在不同的平臺(tái)下,有不同的數(shù)據(jù)庫(kù)訪問(wèn)的手段。例如,在Java平臺(tái)下,有JDBC,在Windows平臺(tái)下,可以使用ADO、ADO.Net等。但是,這些手段還比較接近底層,在實(shí)際操縱數(shù)據(jù)庫(kù)的時(shí)候,需要編寫(xiě)大量的代碼,并且,我們還需要通過(guò)手工的方式來(lái)完成將程序中的面向?qū)ο蟮臄?shù)據(jù)存儲(chǔ)到關(guān)系型數(shù)據(jù)庫(kù)的工作。這么做,自然編程的效率不高,并且非常容易出錯(cuò)。但是,不可否認(rèn),這也是一種可以選用的方式。   從另外一個(gè)方面來(lái)看,由于我們前面已經(jīng)解決了數(shù)據(jù)的映射問(wèn)題,因此,在數(shù)據(jù)的存取方面是非常有規(guī)律的,我們完全可以讓這個(gè)工作通過(guò)框架來(lái)執(zhí)行。這樣,我們一方面可以簡(jiǎn)化很多同數(shù)據(jù)庫(kù)交互方面的代碼編寫(xiě)工作量,能夠減少出現(xiàn)Bug的幾率,另一方面,由于框架封裝了不同數(shù)據(jù)庫(kù)之間的差異,使得我們?cè)诰帉?xiě)程序的時(shí)候,不用考慮不同數(shù)據(jù)庫(kù)之間的差異,而將這個(gè)工作交給框架去做,實(shí)現(xiàn)軟件的后臺(tái)數(shù)據(jù)庫(kù)無(wú)關(guān)性。   在這個(gè)部分,以下兩個(gè)部分的類會(huì)顯得特別重要:   ◆對(duì)象--關(guān)系映射的分析類,能夠通過(guò)既定的方案完成對(duì)象--關(guān)系的映射,確定數(shù)據(jù)存取方案   ◆數(shù)據(jù)庫(kù)操縱類:根據(jù)映射關(guān)系,將數(shù)據(jù)準(zhǔn)確的存儲(chǔ)到數(shù)據(jù)庫(kù)中,并且封裝不同數(shù)據(jù)庫(kù)之間的差異。   這個(gè)部分的操作過(guò)程,可以用圖大概的表示如下:   在J2EE中,這個(gè)部分比較典型的是EntityBean中的CMP。由于在BMP中,同數(shù)據(jù)庫(kù)的交互部分需要通過(guò)手工編寫(xiě)代碼的方式來(lái)實(shí)現(xiàn),因此,很難享受到容器帶來(lái)的便利,只是由于EJB2.0以前的標(biāo)準(zhǔn),CMP的功能,包括映射能力、實(shí)體關(guān)系模式等方面的功能比較弱,所以,在很多時(shí)候,我們不得不使用BMP,F(xiàn)在,EJB2.0,在這個(gè)方面的功能已經(jīng)非常強(qiáng)大了,我們完全可以享受容器帶來(lái)的便利,而將大部分精力放在實(shí)現(xiàn)更加復(fù)雜的業(yè)務(wù)邏輯方面了。   在JDO中,您同樣可以通過(guò)PersistenceManager來(lái)實(shí)現(xiàn)同樣的目標(biāo),例如,您想把一個(gè)Customer對(duì)象保存到數(shù)據(jù)庫(kù)中,可以采用類似于下面的代碼: Customer customer=new Customer(……);PersistenceManager PM=PMFactory.initialize(……);Pm.persist(customer);   代碼同樣非常簡(jiǎn)明和直觀,沒(méi)有一大堆數(shù)據(jù)庫(kù)操縱的代碼,也不容易發(fā)生差錯(cuò)。 Websharp的方案   Webshap為數(shù)據(jù)存取的類定義了IEntityDAO接口,該接口的定義如下: public interface IEntityDAO{void InsertEntity(EntityData entity);void UpdateEntity(EntityData entity);void DeleteEntity(EntityData entity); EntityData FindByPrimaryKey(object KeyValue);} 對(duì)于每一個(gè)實(shí)體類,可以通過(guò)擴(kuò)展這個(gè)接口來(lái)實(shí)現(xiàn)數(shù)據(jù)訪問(wèn)的類。但是,由于這個(gè)接口沒(méi)有提供任何實(shí)現(xiàn)方法,因此,到具體每個(gè)實(shí)現(xiàn)類的時(shí)候,如果是直接擴(kuò)展自這個(gè)接口,實(shí)現(xiàn)的代碼還必須手工填寫(xiě)。為了提高開(kāi)發(fā)效率,減少代碼編寫(xiě)量和出現(xiàn)Bug的可能性,框架提供了AbstractSingleTableDAO和AbstractMultiTableDAO.cs類,這兩個(gè)類擴(kuò)展自IEntityDAO,分別實(shí)現(xiàn)了針對(duì)單個(gè)數(shù)據(jù)庫(kù)表和多個(gè)數(shù)據(jù)庫(kù)表的數(shù)據(jù)庫(kù)訪問(wèn)方法,并且,實(shí)現(xiàn)了IDisposable接口。這樣,我們?cè)趯?shí)際編寫(xiě)代碼的時(shí)候,只需要繼承自這兩個(gè)類可以了。 例如,Customer類的數(shù)據(jù)存取類可以定義如下: public class CustomerEntityDAO:AbstractSingleTableDAO 然后,可以在代碼中這么使用: Customer customer=......using(CustomerEntityDAO CDO=new CustomerEntityDAO()){CDO.UpdateEntity(customer);}   更加一般的,Wensharp也提供了PersistenceManager類,可以用于將EntityData中的數(shù)據(jù)存入數(shù)據(jù)庫(kù)。這個(gè)類包含了兩個(gè)方法:PersistEntity和DeleteEntity。如果不想為某個(gè)實(shí)體類編寫(xiě)專門(mén)的DAO類,那么,也可以使用這個(gè)類來(lái)操縱實(shí)體對(duì)象。不過(guò),目前,只支持映射成單個(gè)表的對(duì)象的自動(dòng)存貯。下面是一個(gè)例子: PersistenceManagerpm=PersistenceManager.Initial();pm. PersistEntity(entity); 為了封裝不同數(shù)據(jù)庫(kù)的操作,統(tǒng)一的數(shù)據(jù)庫(kù)訪問(wèn)接口是必須的。關(guān)于編寫(xiě)通用數(shù)據(jù)庫(kù)訪問(wèn)類的內(nèi)容,可以參見(jiàn)拙作:《使用設(shè)計(jì)模式構(gòu)建通用數(shù)據(jù)庫(kù)訪問(wèn)類》。   在這個(gè)部分,另外需要注意的是,為了保證數(shù)據(jù)存儲(chǔ)的完整性,應(yīng)當(dāng)考慮事務(wù)處理的功能。J2EE、JDO和Websharp都支持在數(shù)據(jù)存儲(chǔ)的時(shí)候使用事務(wù)處理。 業(yè)務(wù)邏輯的處理   有了上面的工作,我們可以把這些對(duì)象組合起來(lái),編寫(xiě)我們的業(yè)務(wù)邏輯。在面向?qū)ο蟮南到y(tǒng)中,業(yè)務(wù)邏輯表現(xiàn)為對(duì)象之間的交互。在一些簡(jiǎn)單的系統(tǒng)中,沒(méi)有復(fù)雜的業(yè)務(wù)邏輯,只是一些數(shù)據(jù)的維護(hù)工作,那么,有了上面兩個(gè)部分的工作,我們實(shí)際上可能已經(jīng)忘成了大部分的工作。   在這個(gè)部分,由于不同系統(tǒng)之間業(yè)務(wù)邏輯千差萬(wàn)別,基本上沒(méi)有辦法提供統(tǒng)一的模式。但是,應(yīng)當(dāng)注意的是,在同一個(gè)系統(tǒng)中,采用基本一致的策略是非常必要的,這有助于項(xiàng)目?jī)?nèi)部的不一致性,使項(xiàng)目更加可控。甚至于,這些策略可以擴(kuò)展成公司部分、甚至所有項(xiàng)目的策略。   值得指出的是,很多人在這個(gè)部分操縱數(shù)據(jù)庫(kù),把業(yè)務(wù)邏輯處理等同于數(shù)據(jù)庫(kù)操作,這是不可取的。在業(yè)務(wù)邏輯處理中,處理的應(yīng)該是對(duì)象,而不是直接同數(shù)據(jù)庫(kù)打交道,這樣,才能獲得更好的系統(tǒng)結(jié)構(gòu)。   在業(yè)務(wù)邏輯處理部分,由框架提供一些支撐的服務(wù)是非常必要的。這其中,最重要的一點(diǎn)是事務(wù)的處理。業(yè)務(wù)邏輯的處理過(guò)程,會(huì)涉及到多個(gè)對(duì)象之間的交互,以及多次同數(shù)據(jù)庫(kù)的交互。為了保證處理過(guò)程的完整性,必須使用事務(wù)處理的方法?蚣鼙仨氈С质聞(wù)處理。   事務(wù)處理的功能,基本上有兩種選擇:使用基于數(shù)據(jù)庫(kù)連接的事務(wù)、使用外部事物處理服務(wù)。   使用基于數(shù)據(jù)庫(kù)連接的事務(wù),事務(wù)處理的性能相對(duì)比較高,但是,當(dāng)系統(tǒng)涉及到多個(gè)數(shù)據(jù)庫(kù)之間的交互時(shí),基于數(shù)據(jù)庫(kù)連接的事務(wù)便無(wú)能為力了。而使用專用的事務(wù)處理服務(wù),能夠適應(yīng)更多的情況,并且,有測(cè)試表明,隨著數(shù)據(jù)處理量的上升,兩者之間的性能差異會(huì)逐漸減小。   在J2EE中,容器提供了事務(wù)處理的能力。在.Net平臺(tái)上,事務(wù)處理是通過(guò)Windows COM+服務(wù)來(lái)提供的。在Websharp中,對(duì)COM+服務(wù)做了一個(gè)簡(jiǎn)單的封裝。同時(shí),也能夠使用基于數(shù)據(jù)庫(kù)連接的事務(wù)。   下面是一個(gè)簡(jiǎn)單的例子,表示了一張入庫(kù)單入庫(kù)的過(guò)程,在這個(gè)過(guò)程中,需要修改入庫(kù)單上每種產(chǎn)品的現(xiàn)有庫(kù)存量: public void StoreIntoWarehouse(EntityData insertForm){insertForm.SetCurrentTable("FormDetail");TransactionManager transManager=new TransactionManager();ProductEntityDAO productDAO=new ProductEntityDAO(true);FormEntityDAO formDAO=new FormEntityDAO(true);try{if(insertForm.CurrentTable.Rows.Count>0)do{string productID=insertForm["ProductID"].ToString();decimal inCount=insertForm.GetDecimal("InCount");EntityData product=productDAO.FindByPrimaryKey(productID);product["CurrentCount"]=product.GetDecimal("CurrentCount")+inCount;transManager.AddMethod(new TransactionManagedFunction(productDAO.UpdateEntity),product);}while(insertForm.Next());transManager.AddMethod(new TransactionManagedFunction(formDAO.InsertEntity),insertForm);transManager.ExecuteMethods();}catch(Exception ee){throw ee;}finally{productDAO.Dispose();insertForm.Dispose();}}   業(yè)務(wù)服務(wù)的提供   業(yè)務(wù)外觀層(Business Facade)的目的,是隔離系統(tǒng)功能的提供者和使用者,更明確地說(shuō),是隔離業(yè)務(wù)邏輯的軟件的用戶界面(可以參見(jiàn)Facade設(shè)計(jì)模式)。這一層沒(méi)有任何需要處理的邏輯,只是作為后臺(tái)邏輯處理和前端用戶界面的緩沖區(qū),以達(dá)到如下目的   ◆將用戶界面和系統(tǒng)業(yè)務(wù)邏輯處理分開(kāi),這樣,當(dāng)業(yè)務(wù)邏輯發(fā)生變化時(shí),不用修改客戶端程序,是一種支持變化的設(shè)計(jì)方法。   ◆使同一個(gè)業(yè)務(wù)邏輯能夠處理不同的客戶端請(qǐng)求。例如,可以將Facade設(shè)計(jì)成Web Service,這樣,可以同時(shí)為傳統(tǒng)的WinForm客戶端程序、Web程序以及其他外部系統(tǒng)提供服務(wù),而使用相同的應(yīng)用服務(wù)層,同時(shí),也可以實(shí)現(xiàn)系統(tǒng)的分布式部署。關(guān)于如何做到這一點(diǎn),可以參見(jiàn)本文所附的Demo程序。   ◆作為系統(tǒng)不同模塊之間的調(diào)用接口。一個(gè)系統(tǒng)通常會(huì)包含很多模塊,這些模塊相對(duì)獨(dú)立,又可能互相調(diào)用。為了減少各個(gè)不同部分之間的耦合度,必須采用一定的設(shè)計(jì)方法,F(xiàn)acade設(shè)計(jì)模式是非常有效的一種,也是業(yè)務(wù)外觀層的基礎(chǔ)。   ◆有利于項(xiàng)目團(tuán)隊(duì)的分工協(xié)作。業(yè)務(wù)外觀層作為一個(gè)訪問(wèn)接口,將界面設(shè)計(jì)人員和邏輯設(shè)計(jì)人員分開(kāi),使得系統(tǒng)的開(kāi)發(fā)可以實(shí)現(xiàn)縱向的分工,不同的開(kāi)發(fā)人員可以關(guān)注自己的領(lǐng)域而不會(huì)受到干擾。   業(yè)務(wù)外觀層的代碼框架,在系統(tǒng)分析和設(shè)計(jì)完成后可以完成,他需要提供的方法,相當(dāng)于在界面設(shè)計(jì)人員和邏輯設(shè)計(jì)人員之間簽訂了一個(gè)協(xié)議,他雖然沒(méi)有實(shí)現(xiàn)任何邏輯,但是,他的引入,能使系統(tǒng)的開(kāi)發(fā)更加有條理,更加簡(jiǎn)明。套用《設(shè)計(jì)模式》上的一句話,是,"任何問(wèn)題,都可以通過(guò)引入一個(gè)中間層來(lái)得到簡(jiǎn)化"。   剪裁和取舍   以上四個(gè)層次,對(duì)于大型的應(yīng)用軟件系統(tǒng)來(lái)說(shuō),是非常必要的。但是,對(duì)于一些小型的應(yīng)用軟件系統(tǒng),如果完全按照以上的層次來(lái)做,可能反而會(huì)影響工作效率。因此,針對(duì)不同的系統(tǒng),可以對(duì)架構(gòu)進(jìn)行一定的剪裁。   數(shù)據(jù)實(shí)體層和實(shí)體控制層,是每個(gè)應(yīng)用軟件系統(tǒng)所必需的,顯然無(wú)法裁減。對(duì)于業(yè)務(wù)邏輯層和業(yè)務(wù)外觀層,根據(jù)實(shí)體情況,可以進(jìn)行如下裁減:   ◆如果系統(tǒng)沒(méi)有復(fù)雜的業(yè)務(wù)邏輯,而只是一些數(shù)據(jù)的操作,或者業(yè)務(wù)邏輯特別少,那么,可以省略業(yè)務(wù)邏輯層,而將相關(guān)的功能移至實(shí)體控制層。   ◆如果不考慮多種客戶端的情況,也不考慮分布式部署的問(wèn)題,系統(tǒng)的模塊又很少,不會(huì)產(chǎn)生模塊間緊耦合的情況,那么,可以不使用業(yè)務(wù)外觀層,而讓用戶界面程序直接訪問(wèn)業(yè)務(wù)功能。   在上面的論述中,對(duì)于每個(gè)層次,都說(shuō)明了可以選擇的多種方案,每一種方案都有他的優(yōu)點(diǎn)和缺點(diǎn),在具體開(kāi)發(fā)的過(guò)程中,需要根據(jù)具體情況加以取舍。   系統(tǒng)外的話   應(yīng)用軟件系統(tǒng)架構(gòu),是軟件工程的重要組成部分。設(shè)計(jì)一個(gè)好的框架,其目的很明確,那是,在目前還沒(méi)有"銀彈"之前,盡的可能,提高軟件開(kāi)發(fā)的效率和軟件質(zhì)量,把不必要的工作和容易出錯(cuò)的工作,交給框架去處理。   應(yīng)用服務(wù)層,在軟件系統(tǒng)中,是一個(gè)非常復(fù)雜的部分,乍看之下,沒(méi)有任何規(guī)律可行,給人無(wú)從下手的感覺(jué)。我們的目標(biāo),是盡量化無(wú)規(guī)律為有規(guī)律,把有規(guī)律的東西提取出來(lái),形成規(guī)范,從而減少今后的開(kāi)發(fā)工作量。其方法,是對(duì)系統(tǒng)進(jìn)行合理的分層,這樣,系統(tǒng)的層次清晰了,每個(gè)層次完成的功能比較單一,意味著每個(gè)層次的都相對(duì)更有規(guī)律可循,這樣,我們可以把這些有規(guī)律的東西交給框架去執(zhí)行,或者,開(kāi)發(fā)一個(gè)輔助工具,來(lái)完成這部分的代碼編寫(xiě)工作。Websharp提供了這樣一個(gè)代碼自動(dòng)生成的工具。這個(gè)工具被設(shè)計(jì)成Visual Studio.Net集成開(kāi)發(fā)環(huán)境的插件,在實(shí)際開(kāi)發(fā)過(guò)程中,能夠提供很多便利。這是系統(tǒng)層次清晰帶來(lái)的另外一個(gè)好處。   對(duì)于一個(gè)軟件公司來(lái)說(shuō),統(tǒng)一的系統(tǒng)框架的意義不僅僅在于軟件開(kāi)發(fā)的本身。一個(gè)統(tǒng)一的系統(tǒng)框架,也是公司知識(shí)管理的重要組成部分。公司如果有一個(gè)或有限個(gè)數(shù)的明確的軟件框架,那么,這些框架可以成為凝結(jié)公司開(kāi)發(fā)人員經(jīng)驗(yàn)、智慧的載體,并且可以在不斷的實(shí)踐中加以充實(shí)和完善。由于公司的軟件系統(tǒng)的框架比較統(tǒng)一,那么當(dāng)某個(gè)項(xiàng)目更換或增加開(kāi)發(fā)人員的時(shí)候,后來(lái)的人也能夠比較容易接手,這對(duì)于公司的開(kāi)發(fā)管理是具有非常重要的意義的。   關(guān)于系統(tǒng)框架同知識(shí)管理的關(guān)系的內(nèi)容,因?yàn)椴皇潜疚牡闹攸c(diǎn),限于篇幅的關(guān)系,所以不再贅述,會(huì)另文加以說(shuō)明。   結(jié)語(yǔ)   應(yīng)用軟件系統(tǒng)的應(yīng)用服務(wù)層是非常復(fù)雜的,為了使得系統(tǒng)的結(jié)構(gòu)更加清晰,找出其中規(guī)律性的東西,需要我們對(duì)系統(tǒng)做進(jìn)一步的層次劃分。對(duì)于每個(gè)層次,都可以有多種設(shè)計(jì)的策略,每一種策略都不可能做到盡善盡美,這需要我們?cè)趯?shí)際中加以取舍。   限于本人的認(rèn)識(shí)和水平,文章中所說(shuō)觀點(diǎn)和方法或有不當(dāng)之處,還請(qǐng)大家能夠指教,一起探討。   附:使用Websharp中間件開(kāi)發(fā)的Demo程序一份。   作者簡(jiǎn)介:孫亞民,1998年畢業(yè)于南京大學(xué),目前中國(guó)科技大學(xué)碩士再讀,蘇州某軟件公司技術(shù)總監(jiān),可以通過(guò)sunny_y_m@163.com 同他聯(lián)系。
立即預(yù)約