l轉(zhuǎn)自:http://www.lvjiyong.com/books/OODesigner/孫亞民目錄第一部分綜述4第1章本書會討論什么內(nèi)容5第2章系統(tǒng)的分層結(jié)構(gòu)82.1.簡述82.2.設(shè)計的原則和評判標準92.3.應(yīng)用服務(wù)層的內(nèi)容102.4.數(shù)據(jù)實體的表示112.5.數(shù)據(jù)的存取方式152.6.業(yè)務(wù)邏輯的處理182.7.業(yè)務(wù)服務(wù)的提供202.8" />

日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

構(gòu)建面向?qū)ο蟮膽?yīng)用軟件系統(tǒng)框架

系統(tǒng) 2681 0
<style type="text/css"> <!-- body { margin-top: 0px; } --> </style>
l
轉(zhuǎn)自:http://www.lvjiyong.com/books/OODesigner/
孫亞民
目錄
第一部分 綜述 4
第1章本書會討論什么內(nèi)容 5
第2章系統(tǒng)的分層結(jié)構(gòu) 8
2.1.簡述 8
2.2.設(shè)計的原則和評判標準 9
2.3.應(yīng)用服務(wù)層的內(nèi)容 10
2.4.數(shù)據(jù)實體的表示 11
2.5.數(shù)據(jù)的存取方式 15
2.6.業(yè)務(wù)邏輯的處理 18
2.7.業(yè)務(wù)服務(wù)的提供 20
2.8.層的部署和層間交互 20
2.9.剪裁和取舍 21
2.10.小結(jié) 21
第二部分 應(yīng)用服務(wù)層的設(shè)計 23
第3章數(shù)據(jù)和對象 24
3.1數(shù)據(jù)的形態(tài) 24
3.2對象/關(guān)系型映射 26
3.3對象的狀態(tài) 28
Transient 28
Persistent-new 29
Persistent-dirty 29
Persistent-clean 29
Persistent-deleted 29
第4章 O/R Mapping的一般做法 31
第5章設(shè)計一個O/R Mapping框架 40
5.1封裝數(shù)據(jù)庫訪問層 40
5.2設(shè)計映射 48
5.3 對繼承的支持 55
5.4設(shè)計對象操縱框架 61
5.5實現(xiàn)對象操縱框架 66
第6章面向方面編程 71
6.1 AOP概念 71
6.2 Websharp AOP的使用 73
6.2.1.使用AOP實現(xiàn)松散耦合 73
6.2.2.使用AOP組合兩個業(yè)務(wù)邏輯 76
6.3 Websharp AOP的實現(xiàn) 76
6.3.1 AspectObject抽象類 78
6.3.2 IAspect接口 78
6.3.3 AspectManagedAttribute 78
6.3.4 定義AspectProxy類 80
6.3.5 其他一些輔助類 80
6.3.6 配置文件 80
6.4 關(guān)于AOP和過濾器 81
6.5 小結(jié) 82
第7章接口 83
第8章事務(wù)處理 86
8.1 事務(wù)的基本概念 86
8.2 實際開發(fā)中可用的事務(wù)處理方式 88
第9章性能優(yōu)化 101
第三部分 用戶界面層設(shè)計 102
第10章 界面層的功能劃分 103
第11章 界面設(shè)計模式 104
11.1 MVC模式 104
11.2 頁面控制器 107
第12章 動態(tài)代碼生成和編譯技術(shù) 108
12.1 Emit 108
12.2 CodeDom 108
第13章 遠程過程訪問的客戶端整合 111
Web Service 111
.Net Remoting 112
Websharp Service Locator的主要接口 114
Websharp Service Locator的配置文件 114
如何使用Websharp Service Locator 116
LocalAssemblyLocator 的Hello World例子 116
Hello World 的WebServiceLocator例子 118
Websharp Service Locator的實現(xiàn) 120
目前的進展 120
將來的目標 120
小結(jié) 120
第14章 智能客戶端 122
小結(jié) 128
第四部分 系統(tǒng)建模過程 129
第15章 簡述 130
第16章 用例模型——系統(tǒng)需求的獲取 131
第17章 分析模型——開發(fā)者的視野 135
第18章 系統(tǒng)設(shè)計——實現(xiàn)方案 141


本書會討論什么內(nèi)容
從軟件工程說起。提起這個概念,往往令人想起CMM、RUP、印度模式等。管理的因素,在軟件開發(fā)過程中起著非常重要的作用,然而,軟件工程并 非只指軟件開發(fā)的管理工作,而是一個范圍很廣的綜合性學科。在軟件工程中,大約一半的內(nèi)容是專業(yè)性很強的,涉及到軟件分析、設(shè)計甚至編碼的技術(shù)。所謂的結(jié) 構(gòu)化、面向?qū)ο螅荚谲浖こ痰姆懂爟?nèi)。“軟件工程范圍極為廣泛。軟件工程的某些方面屬于數(shù)學或計算機科學,其他方面可歸入經(jīng)濟學、管理學或心理學中。”
軟件業(yè)一直在探討,如何使軟件實現(xiàn)如同傳統(tǒng)產(chǎn)業(yè)一樣的大規(guī)模生產(chǎn)。軟件工程的提出,便是為了實現(xiàn)這個愿望。然而,雖然軟件工程至今已經(jīng)有了很大的發(fā)展,軟件的大規(guī)模工業(yè)化生產(chǎn)仍然沒有實現(xiàn)。原因何在?
從軟件的本質(zhì)屬性來說,軟件的復(fù)雜性是軟件的本質(zhì)屬性,在這個屬性沒有改變之前,軟件便不會實現(xiàn)同傳統(tǒng)產(chǎn)業(yè)一樣的工廠化生產(chǎn)。
從軟件生產(chǎn)的介質(zhì)來說,傳統(tǒng)產(chǎn)業(yè)生產(chǎn)都是有形的物質(zhì)產(chǎn)品,人的生產(chǎn)活動都受制于生產(chǎn)資料這些物質(zhì)介質(zhì);然而,軟件生產(chǎn)的介質(zhì),卻是無形的人類的 思維。物質(zhì)資料的生產(chǎn),受制于物質(zhì)本身的屬性,不容易為人類的思維所左右,并且容易被大量復(fù)制,這使得工業(yè)化大生成為可能。而人類的思維,卻是如此的容易 變化,更關(guān)鍵的是不能被復(fù)制,甚至同一個人,不同時期思維的復(fù)制都不可能,這使得軟件這個純粹依賴人的思維活動的生產(chǎn)實現(xiàn)大規(guī)模工業(yè)化生產(chǎn)是如此的困難。 實際上,不僅僅是軟件產(chǎn)業(yè),凡是主要生產(chǎn)介質(zhì)是人本身的活動的產(chǎn)業(yè),都很難實現(xiàn)工業(yè)化生產(chǎn),如咨詢、演藝等。
從生產(chǎn)過程來看,對于傳統(tǒng)產(chǎn)業(yè)來說,產(chǎn)品的設(shè)計和生產(chǎn)是分開的。在設(shè)計階段,主要的工作是人的思維,因此,在這個階段,同軟件一樣,不是批量生 產(chǎn)的。而在生產(chǎn)階段,主要的對象便是物質(zhì)資料,并且一切標準已經(jīng)制定,只需要在流水線上大量復(fù)制。對于傳統(tǒng)產(chǎn)業(yè)來說,設(shè)計和生產(chǎn)的界限是如此的明確,并 且,生產(chǎn)和設(shè)計的比重是如此的懸殊。然而,對于軟件產(chǎn)業(yè)來說,軟件的生產(chǎn)過程便是設(shè)計的過程,純粹的生產(chǎn)過程幾乎不存在(或許,光盤的復(fù)制算是),這使得 軟件的生產(chǎn)形態(tài)同傳統(tǒng)產(chǎn)業(yè)必然存在區(qū)別。
對于軟件的開發(fā)過程來說,從業(yè)務(wù)模型、需求分析、系統(tǒng)架構(gòu)、系統(tǒng)分析和設(shè)計、到最后代碼實現(xiàn),越往前,抽象層次越高,可控性越小,越往后,越接 近實際,可控性越大,因此,在軟件開發(fā)中,核心團隊的作用是如此巨大,一個軟件產(chǎn)品的成敗,核心團隊的核心人員的作用在很大程度上是決定性的。對于軟件開 發(fā)來說,如果軟件開發(fā)要實現(xiàn)工業(yè)化生產(chǎn),必定是從后向前推進,從編碼開始。印度模式或許給出了這么一個例子。
因此,我們在軟件工程的路上,只是在不斷的向工程化的目標邁進,但是,要達到這個目標,可能會花很長的時間。技術(shù)上的每一次進步,都使我們向這 個目標邁進了一步。在軟件工程的發(fā)展過程中,技術(shù)進步起了非常大,甚至可以說是決定性的作用。隨著采用的技術(shù)的不同,所采用的管理方法也在不斷變化。軟件 工程技術(shù)的很多方面,也是為管理做準備的。優(yōu)秀的軟件開發(fā)技術(shù)的采用,能夠彌補我們在工程化方面的不足,從而使得軟件開發(fā)更加可控,軟件質(zhì)量更加有保障。
本書不準備討論軟件工程過程的問題,而只是對軟件工程中軟件技術(shù)的一個方面——系統(tǒng)框架設(shè)計,做一些探討。
現(xiàn)在,很多開發(fā)人員都已經(jīng)意識到這很重要的一點,那就是,在開發(fā)一個應(yīng)用軟件系統(tǒng)的時候,一個好的系統(tǒng)框架是非常重要的。從底層開始構(gòu)建應(yīng)用程序,是一件吃力不討好的事情,而沒有框架的應(yīng)用程序,則很難想象會是一個好的應(yīng)用程序。
除了對于開發(fā)的直接幫助,一個好的框架對于公司的知識管理也是非常有意義的。想象一下,我們經(jīng)常在討論,現(xiàn)在是一個知識經(jīng)濟的時代,尤其對于軟件公司來說,知識(擁有這些知識的員工)就是公司最大的財富。那么,怎么來進行有效的知識管理呢?
首先,應(yīng)當明確,知識管理,一個重要的目的,就是要把員工對公司最重要的知識沉淀下來。公司的每個員工頭腦里都有很多的知識,這些知識對于員工 來說是很重要的,但是其重要性同公司并不是完全一致的。某些知識,對于某個員工來說是最重要的,但是對于公司可能并不需要。知識管理需要做的,是把員工對 公司最重要的知識累積起來。
其次,知識管理必須有一個載體。如果知識管理沒有載體,那么,公司的知識就存在于員工的頭腦之中,一旦這個員工離職,那么,知識也就離去了,沒 有辦法沉淀。如果只是把公司做過的項目的文檔作為載體,那么,這個載體就過于零碎了。實際上,如果公司有一個統(tǒng)一的框架,那么,這個框架就是一個很好的知 識管理的載體。因為,這個框架,必定是集中了公司所有軟件項目的共同點的,集中了對于公司最重要的知識的精華,能夠為公司所有的項目服務(wù)。另外,隨著框架 的不斷被使用,框架本身也會隨之升級優(yōu)化。對于一個新成員的加入,他只要理解掌握了這個框架,就可以很好的融入團隊中來;而人員的離去,也已經(jīng)把自己對公 司最重要的知識留在了這個框架中。可以說,在這里,框架承擔了一個知識管理平臺的作用。一個最好的例子就是微軟的Windows。這是微軟所有知識的最集 中的平臺。
軟件,從本質(zhì)上來說,就是現(xiàn)實世界在計算機中的模擬。在考慮應(yīng)用軟件系統(tǒng)架構(gòu)的時候,實際上,考慮的問題主要在于:處理什么?怎么處理?如何使用?因此,應(yīng)用軟件系統(tǒng),需要關(guān)注的方面,概括起來,主要包括以下三個大類:
處理的對象,也就是數(shù)據(jù)。
處理的方式,也就是我們的系統(tǒng)如何來處理系統(tǒng)的邏輯。
如何進行交互,這個交互包括用戶(使用者),以及外部系統(tǒng)。
在應(yīng)用軟件系統(tǒng)中,數(shù)據(jù)是處理的基本對象,程序總是以一定的數(shù)據(jù)結(jié)構(gòu)來表現(xiàn)數(shù)據(jù),并且,在使用面向?qū)ο笳Z言開發(fā)的系統(tǒng)中,數(shù)據(jù)總是以類和對象的 形式表現(xiàn)出來。另外一方面,數(shù)據(jù)總是需要存儲,對于大部分應(yīng)用軟件系統(tǒng)來說,通常會采用關(guān)系型數(shù)據(jù)庫來保存數(shù)據(jù)。這樣,由于數(shù)據(jù)在程序和數(shù)據(jù)庫中表現(xiàn)格式 的不一致,就必然要求在兩者之間進行映射。這個映射,在面向?qū)ο笤O(shè)計語言和關(guān)系型數(shù)據(jù)庫之間,通常稱為對象/關(guān)系型映射,即O/R Mapping。
目前,在O/R Mapping部分,在Java平臺下,已經(jīng)有多種可以選擇的方案,例如J2EE架構(gòu)中的Entity Bean,輕量級的JDO,以及開源項目的Hibernate等,由于微軟的.Net框架推出時間不長,成熟的O/R Mapping框架并不多見。O/R Mapping框架的選擇或者設(shè)計是構(gòu)建應(yīng)用軟件系統(tǒng)的最基本的工作。本書將討論構(gòu)建O/R Mapping框架的一些基本理論、概念和方法。
系統(tǒng)的業(yè)務(wù)邏輯處理,是應(yīng)用軟件系統(tǒng)的核心部分,如何合理的構(gòu)建業(yè)務(wù)邏輯、如何提供業(yè)務(wù)邏輯層的服務(wù),以及表現(xiàn)層如何訪問業(yè)務(wù)邏輯提供的功能, 也是應(yīng)用軟件系統(tǒng)需要重點關(guān)注的問題。在這個方面,業(yè)界已經(jīng)發(fā)展了很多可供選擇的范式,如契約式設(shè)計、SOA架構(gòu)(面向服務(wù)的架構(gòu))等。這些方法指明了設(shè) 計的方向,同時也需要我們在實際開發(fā)中加以應(yīng)用。
在業(yè)務(wù)邏輯確定后,隨后而來的問題就是,如何向客戶端來提供業(yè)務(wù)邏輯服務(wù),或者說,客戶端如何訪問這些服務(wù)。在多層應(yīng)用軟件系統(tǒng)中,客戶端和業(yè) 務(wù)邏輯在物理上可能存在于不同的機器上,也可能存在于同一臺機器,但至少,在邏輯上,是存在于兩個不同部分,這就涉及到一個問題:這兩個層之間如何進行通 信?還會涉及到遠程過程調(diào)用的問題。
當然,現(xiàn)在我們已經(jīng)有多種技術(shù)來遠程過程調(diào)用,包括Webservice、.Net Remoting、Corba、甚至EJB等。如此多的實現(xiàn)技術(shù),帶來的很大的靈活性,但同時也帶來了問題,其中一個就是,有多少種服務(wù)端技術(shù),就得有多 少種相應(yīng)的客戶端訪問技術(shù)。甚至,在某些分布式應(yīng)用系統(tǒng)中,應(yīng)用邏輯使用不同的技術(shù)開發(fā),存在于不同的機器上,有的存在于客戶機本機,有的使用.Net Remoting開發(fā),存在于局域網(wǎng)內(nèi),有的使用因特網(wǎng)上的Web Service,有的時候,我們希望相同的業(yè)務(wù)邏輯能夠支持不同的客戶端。
在這種情況下,我們需要一個一致的服務(wù)訪問編程模型,以統(tǒng)合不同的服務(wù)訪問模式,簡化系統(tǒng)的開發(fā)和部署。一個統(tǒng)一的遠程過程調(diào)用框架的前景是如 此的誘人,以至于每一種方法都試圖一統(tǒng)天下,但出于種種原因,最終都沒有一家能夠做到,最新的Web Service就力圖做到這一點。實際上,每一種方法的出現(xiàn),最終都會帶來一個副作用,那就是,可供選擇的多了一點,混亂也就又多了一點。在實際的開發(fā)過 程中,我們也需要一個統(tǒng)一的訪問方式來解決這個問題。本書將討論一些可用的方案。
為了更加清晰的進行表述,文章會附加一些程序代碼。因為在講到具體的技術(shù)的時候,本書會對各種可用的技術(shù)進行比較,因此,本書的代碼可能會使用 不同的語言,通常是Java和C#,不過,在給出代碼的時候,一般都會指明所用的語言。在大部分情況下,如果不說明具體的語言,那么就是C#(因為我比較 喜歡這門語言)。因為Java和C#的語法是如此的相像,我想,對有經(jīng)驗的程序員來說,這應(yīng)該不會造成閱讀上的麻煩。

系統(tǒng)的分層結(jié)構(gòu)
2 .1.簡述
我們在解決一個復(fù)雜的問題的時候,通常使用的一個技巧就是分解,把復(fù)雜的問題分解成為若干個簡單的問題,逐步地、分別地解決這幾個小問題,最后 就把整個問題解決掉。在設(shè)計一個復(fù)雜的軟件系統(tǒng)的時候,同樣的,為了簡化問題,我們也通常使用的一個技術(shù)就是分層,每個層完成自身的功能,最后,所有的層 整合起來構(gòu)成一個完整的系統(tǒng)。
分層是計算機技術(shù)中的常用方法,一個典型的例子就是TCP/IP技術(shù)的OSI七層模型。在應(yīng)用軟件開發(fā)中,典型的就是N層應(yīng)用軟件模型。N層的應(yīng)用軟件系統(tǒng),由于其眾多的優(yōu)點,已經(jīng)成為典型的軟件系統(tǒng)架構(gòu),也已經(jīng)為廣大開發(fā)人員所熟知。
在一個典型的三層應(yīng)用軟件系統(tǒng)中,應(yīng)用系統(tǒng)通常被劃分成以下三個層次:數(shù)據(jù)庫層、應(yīng)用服務(wù)層和用戶界面層。如下圖(圖2.1)所示:
圖2.1
其中,應(yīng)用服務(wù)層集中了系統(tǒng)的業(yè)務(wù)邏輯的處理,因此,可以說是應(yīng)用軟件系統(tǒng)中的核心部分。軟件系統(tǒng)的健壯性、靈活性、可重用性、可升級性和可維護性,在很大程度上取決于應(yīng)用服務(wù)層的設(shè)計。因此,如何構(gòu)建一個良好架構(gòu)的應(yīng)用服務(wù)層,是應(yīng)用軟件開發(fā)者需要著重解決的問題。
為了使應(yīng)用服務(wù)層的設(shè)計達到最好的效果,我們通常還需要對應(yīng)用服務(wù)層作進一步的職能分析和層次細分。很多開發(fā)者在構(gòu)建應(yīng)用服務(wù)層的時候,把數(shù)據(jù) 庫操縱、業(yè)務(wù)邏輯處理甚至界面顯示夾雜在一起,或者,把業(yè)務(wù)邏輯處理等同于數(shù)據(jù)庫操縱,等等,這些,都是有缺陷的做法。我們將就在這個方面進行設(shè)計時可采 用的方案進行一些探討。
在一個分布式應(yīng)用系統(tǒng)中,整個系統(tǒng)會部署在不同的物理設(shè)備上,如上面所示的三層體系,用戶界面和應(yīng)用服務(wù)器可能在不同的設(shè)備上,這就涉及到不同 機器之間的通信問題,也就是層間的通信和交互問題。我們已經(jīng)有了很多可以用于分布式遠程訪問的技術(shù),如CORBA,在Java平臺上,我們還有Java RMI、EJB,在Windows平臺上,從DCOM到COM+,再到.Net下的Web Service和.Net Remoting等。如何選用合適的遠程訪問技術(shù),也是我們在系統(tǒng)框架中需要考慮的問題。[6]
  為了使討論更具有針對性,本文也會討論一些比較流行的系統(tǒng)架構(gòu),例如J2EE架構(gòu),以及JDO,然后,我們會討論Websharp在這個方面的一些設(shè)計理念。
2 .2.設(shè)計的原則和評判標準
  同軟件工程的原則一樣,應(yīng)用服務(wù)層的設(shè)計,必須遵循的最重要的原則就是高內(nèi)聚和低耦合[7]。軟件分層的本來目的,就是提高軟件的可維護性 和可重用性,而高內(nèi)聚和低耦合正是達成這一目標必須遵循的原則。盡量降低系統(tǒng)各個部分之間的耦合度,是應(yīng)用服務(wù)層設(shè)計中需要重點考慮的問題。
  內(nèi)聚和耦合,包含了橫向和縱向的關(guān)系。功能內(nèi)聚和數(shù)據(jù)耦合,是我們需要達成的目標。橫向的內(nèi)聚和耦合,通常體現(xiàn)在系統(tǒng)的各個模塊、類之間的關(guān)系,而縱向的耦合,體現(xiàn)在系統(tǒng)的各個層次之間的關(guān)系。
  系統(tǒng)的框架,通常包含了一系列規(guī)范、約定和支撐類庫、服務(wù)。
  對于如何判斷一個軟件的系統(tǒng)框架的優(yōu)劣,筆者認為,可以從以下幾個方面來評判:
  ◆ 系統(tǒng)的內(nèi)聚和耦合度
  這是保證一個系統(tǒng)的架構(gòu)是否符合軟件工程原則的首要標準。
  ◆ 層次的清晰和簡潔性
  系統(tǒng)每個部分完成功能和目標必須是明確的,同樣的功能,應(yīng)該只在一個地方實現(xiàn)。如果某個功能可以在系統(tǒng)不同的地方實現(xiàn),那么,將會給后來的開發(fā)和維護帶來問題。
  系統(tǒng)應(yīng)該簡單明了,過于復(fù)雜的系統(tǒng)架構(gòu),會帶來不必要的成本和維護難度。在盡可能的情況下,一個部分應(yīng)該完成一個單獨并且完整的功能。
  ◆ 易于實現(xiàn)性
  如果系統(tǒng)架構(gòu)的實現(xiàn)非常困難,甚至超出團隊現(xiàn)有的技術(shù)能力,那么,團隊不得不花很多的精力用于架構(gòu)的開發(fā),這對于整個項目來說,可能會得不償失。簡單就是美。
  ◆ 可升級和可擴充性
  一個系統(tǒng)框架,受設(shè)計時技術(shù)條件的限制,或者設(shè)計者本人對系統(tǒng)認識的局限,可能不會考慮到今后所有的變化。但是,系統(tǒng)必須為將來可能的變化做好準備,能夠在今后,在目前已有的基礎(chǔ)上進行演進,但不會影響原有的應(yīng)用。接口技術(shù),是在這個方面普遍應(yīng)用的技巧。
  ◆ 是否有利于團隊合作開發(fā)
  一個好的系統(tǒng)架構(gòu),不僅僅只是從技術(shù)的角度來看,而且,它還應(yīng)該適用于團隊開發(fā)模型,可以方便一個開發(fā)團隊中各個不同角色的互相協(xié)作。例如,將Web頁面和業(yè)務(wù)邏輯組件分開,可是使頁面設(shè)計人員和程序員的工作分開來同步進行而不會互相影響。
  ◆ 性能
  性能對于軟件系統(tǒng)來說是很重要的,但是,有的時候,為了能讓系統(tǒng)得到更大的靈活性,可能不得不在性能和其他方面取得平衡。另外一個方面,由于硬件技術(shù)的飛速發(fā)展和價格的下降,性能的問題往往可以通過使用使用更好的硬件來獲得提升。
2 .3.應(yīng)用服務(wù)層的內(nèi)容
  應(yīng)用服務(wù)層,通常也被稱為業(yè)務(wù)邏輯層,因為這一層,是應(yīng)用軟件系統(tǒng)業(yè)務(wù)邏輯處理集中的部分。然而,我將這一層稱為應(yīng)用服務(wù)層,而不稱業(yè)務(wù)邏輯層,因為,這一層需要處理的不僅僅是業(yè)務(wù)邏輯,還包含了其他方面的內(nèi)容。
  從完整的角度來說,應(yīng)用服務(wù)層需要處理以下內(nèi)容:
  ◆ 數(shù)據(jù)的表示方式
  數(shù)據(jù),是軟件處理的對象。從某種程度上來說,"軟件,就是數(shù)據(jù)結(jié)構(gòu)加算法"的說法,是有一定意義的。在面向?qū)ο蟮南到y(tǒng)中,數(shù)據(jù)是用類來表示 的,代表了現(xiàn)實世界實體對象在軟件系統(tǒng)中的抽象。考慮所謂的MVC模式,這個部分的類屬于M--實體類的范疇。由于應(yīng)用軟件通常會使用數(shù)據(jù)庫,數(shù)據(jù)庫中的 數(shù)據(jù),可以看成是對象的持久化保存。由于數(shù)據(jù)庫一般是關(guān)系型的,因此,這個部分,還需要考慮類(對象)同關(guān)系型數(shù)據(jù)的映射,即通常所說的O-R MAP問題。
  ◆ 數(shù)據(jù)的存取方式
  如同上述所說,軟件系統(tǒng)處理的實體對象數(shù)據(jù)需要持久化保存數(shù)據(jù)庫中,因此,我們必須處理系統(tǒng)同數(shù)據(jù)庫的交互,以及數(shù)據(jù)的存取和轉(zhuǎn)換方式的問題。
  ◆ 業(yè)務(wù)邏輯的組織方式
  在面向?qū)ο蟮南到y(tǒng)中,業(yè)務(wù)邏輯表現(xiàn)為對象之間的交互。有了上述的實體對象,以及對象的保存策略,就可以將這些對象組合起來,編寫我們的業(yè)務(wù) 邏輯處理程序。在業(yè)務(wù)邏輯的處理中,必須保證處理的正確性和完整性,這將會涉及到事務(wù)處理。通常,我們也會把業(yè)務(wù)邏輯封裝成組件的形式,以得到最大的可重 用性。
  ◆ 業(yè)務(wù)服務(wù)的提供方式
  在我們完成系統(tǒng)的功能后,如何向客戶提供服務(wù),是我們需要考慮的問題。這里的客戶,不僅僅是指軟件的使用者,也包括調(diào)用的界面、其他程序 等。例如,在一個基于Web的ASP.Net或JSP系統(tǒng)中,業(yè)務(wù)邏輯功能的客戶便是這些ASP.Net頁面或JSP頁面。業(yè)務(wù)邏輯組件應(yīng)該通過什么方 式,直接的,或間接的,向這些客戶提供服務(wù),是這一層需要完成的任務(wù)。
  ◆ 層的部署和層間交互
  對于一個多層的應(yīng)用軟件系統(tǒng)來說,尤其是大型的應(yīng)用軟件系統(tǒng),通常需要把不同的部分部署在不同的邏輯或物理設(shè)備上。特別是一些基于Web的 應(yīng)用軟件系統(tǒng),其部署工作將涉及到Web服務(wù)器、組件服務(wù)器、數(shù)據(jù)庫服務(wù)器等不同的服務(wù)設(shè)備。在進行應(yīng)用軟件架構(gòu)的設(shè)計的時候,必須考慮各種不同的部署方 案。 當系統(tǒng)需要進行分布式訪問的時候,如何統(tǒng)一和簡化分布式系統(tǒng)的開發(fā),便成了系統(tǒng)框架需要考慮的內(nèi)容。
  綜上所述,一個完整的基于Web的應(yīng)用軟件系統(tǒng),其架構(gòu)可以用圖2.2來表示(Websharp的應(yīng)用軟件系統(tǒng)架構(gòu)):

圖2.2
對于以上各個方面來說,每個問題都可以有很多種策略和方案,但是,在一個系統(tǒng)中,應(yīng)該盡可能的統(tǒng)一這些策略和方案。也就是說,在一個系統(tǒng),或者 一個項目中,應(yīng)該統(tǒng)一每個解決每個問題所采用的方法。軟件的開發(fā)方法是靈活的,可以用不同的方法解決相同的問題,這會誘使開發(fā)人員采用他們認為能夠表現(xiàn)自 己的方法,但是,從整個系統(tǒng)來看,這將會是災(zāi)難性的。我們應(yīng)該盡可能統(tǒng)一,就是,采用統(tǒng)一的數(shù)據(jù)表示方式、統(tǒng)一的數(shù)據(jù)存取方式、統(tǒng)一的業(yè)務(wù)邏輯處理方式 等。
下面,將就這些部分的設(shè)計策略和可用方案進行一些比較詳細的論述。
2 .4.數(shù)據(jù)實體的表示
  應(yīng)用軟件系統(tǒng),從本質(zhì)上來說,是計算機對現(xiàn)實世界的模擬。現(xiàn)實世界中的實體對象,在軟件系統(tǒng)中,表現(xiàn)為需要處理的數(shù)據(jù)。在面向?qū)ο蟮南到y(tǒng)中,這是通過“類"和”對象"來表示的。
  參考著名的“MVC”模式[8],類可以分成實體類(M)、控制類(C)、和邊界類(V),分別代表了實體對象、控制和界面顯示。系統(tǒng)中需要處理的數(shù)據(jù),在面向?qū)ο蟮南到y(tǒng)中,屬于實體類部分。
  在考慮數(shù)據(jù)實體層的設(shè)計策略的時候,需要把握以下要點:
  ◆ 一致的數(shù)據(jù)表示方式。在一個系統(tǒng)中,數(shù)據(jù)的表示方式必須盡可能統(tǒng)一,同時,在處理單個數(shù)據(jù)和多個數(shù)據(jù)的時候,處理方式盡可能一致。
  ◆ 因為數(shù)據(jù)通常是需要存儲到數(shù)據(jù)庫中,因此,良好的映射方法是必需的。
  ◆ 處理好對象的粒度,即所謂的粗粒度對象、細粒度對象。
  一般例子
  考慮一個現(xiàn)實的例子,一個倉庫中的產(chǎn)品(Product),在系統(tǒng)中可以使用如下定義:
public class Product
{
public string Name; //名稱
public decimal Price;//價格
public int Count;//數(shù)量
}
可以按照如下方法使用Product類:
Product p=new Product();
//……處理Product
  這是一個包含了三個屬性的Product類的定義。為了便于說明,在這里,我們盡量將問題簡化了。
  又例如,一張入庫單可以使用如下定義:
public class Form
{
public string ID; //入庫單編號
public DateTime AddTime; //入庫時間
public FormDetail[] FormDetails; //入庫單明細
}
public class FormDetail
{
public Product InProduct; //入庫產(chǎn)品
public int Count; //入庫數(shù)量
}
  對于處理單個對象,通常采用上述的方法,但是,當我們需要處理相同類的一組對象,也就是處理一個對象集合的時候,就會有一些小小的麻煩。
  如前所述,我們希望在處理單個對象和對象集合的時候,處理的方式盡量統(tǒng)一,這對于軟件開發(fā)的意義是很大的。常用的處理對象集合的方法有:
  ◆數(shù)組表示的方法
  例如,上面的例子中當一張入庫單包含多條入庫單明細的時候采用的方法。為了靈活性,也可以使用容器來,如Java中的Vector或C#的 ArrayList(C#)。只是,在處理對象的時候,需要一個類型轉(zhuǎn)換的操作。這個問題,在支持泛型的語言中不會存在,如使用C++的標準庫的容器類。
ObjectCollection方法。
這個方法同上面的方法類似,不同之處在于,為每個實體類設(shè)計一個Collection類。例如,可以為FormDetail設(shè)計一個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];
}
}
}
  這么做的好處在于,在操作集合中的對象時,不必進行類型轉(zhuǎn)換的操作。
  ◆數(shù)據(jù)集的表示方法。
  采用這種方法,通常是直接把從數(shù)據(jù)庫查詢中獲取的數(shù)據(jù)集(Recordset)作為數(shù)據(jù)處理對象。這種方法在ASP應(yīng)用程序中是非常常見的做法。這種做法簡單,初學者很容易掌握,但是他不是一種面向?qū)ο蟮姆椒ǎ撞∫埠芏唷?
  EJB的方法
  在J2EE體系中,對實體對象的處理的典型方法是Entity Bean。J2EE中使用Entity Bean來表示數(shù)據(jù),以及封裝數(shù)據(jù)的持久化儲存(同數(shù)據(jù)庫的交互)。由于Entity Bean比較消耗資源,而且采用的是遠程調(diào)用的方式來訪問,因此,在需要傳遞大量數(shù)據(jù),或者在不同的層次之間傳遞數(shù)據(jù)的時候,往往還會采用一些諸如"值對 象"(Value Object)的設(shè)計模式來提升性能。關(guān)于J2EE中的設(shè)計模式的更多內(nèi)容,可以參考《J2EE核心模式》一書。 [9]
  JDO的方法
  相對于J2EE這個昂貴的方法來說,JDO提供了一個相對"輕量級"的方案。在JDO中,你可以采用一般的做法,編寫實體類,然后,通過一 些強化器對這些類進行強化,以使其符合JDO的規(guī)范,最后,你可以通過PersistenceManager來實現(xiàn)對象的持久化儲存。 [10]
  無論是EJB還是JDO,在同數(shù)據(jù)庫進行映射的時候,都選用了XML配置文件的方式。這是一種靈活的方式。由于XML強大的表達能力,我們 可以很好的用它來描述代碼中的實體類和數(shù)據(jù)庫之間的映射關(guān)系,并且,不用在代碼中進行硬編碼,這樣,在情況發(fā)生變化的時候,有可能只需要修改配置文件,而 不用去修改程序的源代碼。關(guān)于EJB和JDO的配置文件的更多的信息,各位可以參考相關(guān)的文檔,這里不再贅述了。
  然而,使用XML配置文件的方式并不是唯一的方法,在微軟提供的一些案例中,如Duwamish示例[11],就沒有采用這種方式。至于開發(fā)人員在開發(fā)過程中具體采用哪種方式,是需要根據(jù)具體情況進行權(quán)衡和取舍的。
  Websharp的方法
Websharp在數(shù)據(jù)的表現(xiàn)上,充分利用了.Net Framework類庫中DataSet和特性(Attribute)的功能。我們設(shè)計了一個EntityData類,這個類繼承了DataSet,并增加了一些屬性和方法。
在Websharp中,當表示一個實體類的時候,需要定義一個抽象類,這個抽象類繼承PersistenceCapable。例如,一個Schdule類可以表示如下:
[TableMap("Schdule","GUID")]
[WebsharpEntityInclude(typeof(Schdule))]
public abstract class Schdule : PersistenceCapable
{
[ColumnMap("GUID",DbType.String,"")]
public abstract string GUID{get;set;}
[ColumnMap("UserID",DbType.String,"")]
public abstract string UserID{get;set;}
[ColumnMap("StartTime",DbType.DateTime)]
public abstract DateTime StartTime{get;set;}
[ColumnMap("EndTime",DbType.DateTime)]
public abstract DateTime EndTime{get;set;}
[ColumnMap("Title",DbType.String,"")]
public abstract string Title{get;set;}
[ColumnMap("Description",DbType.String,"")]
public abstract string Description{get;set;}
[ColumnMap("RemidTime",DbType.DateTime)]
public abstract DateTime RemidTime{get;set;}
[ColumnMap("AddTime",DbType.DateTime)]
public abstract DateTime AddTime{get;set;}
[ColumnMap("Status",DbType.Int16,0)]
public abstract short Status{get;set;}
}
類的TableMap 特性指明了同Schdule實體類相映射的數(shù)據(jù)庫表,以及關(guān)鍵字,ColumnMap特性指明了同某個屬性相映射的數(shù)據(jù)庫表字段,以及數(shù)據(jù)類型和默認值。
在實際的應(yīng)用中,定義了這樣一個Schdule抽象類后,要獲取一個實體對象,因為Schdule類是抽象的,所以你不可以直接使用new操作來初始化Schdule對象,應(yīng)當通過如下方式取得:
Schdule schdule = EntityManager.CreateObject(typeof(Schdule)) as Schdule;
EntityManager會即時編譯出一個Schdule的實現(xiàn)類,并且返回一個對象。
在這種方式下,實體類同數(shù)據(jù)庫表的映射是通過Attribute來實現(xiàn)的。
可以使用另外一種方法來表示一個實體類。在這種方式下,需要編寫一個XML映射文件,然后,可以使用如下方式取得一個實體對象:
EntityData schdule =EntityManager.GetEntityData("Schdule");
然后,可以通過如下方式來訪問這個對象的屬性:
string Title = schdule["Title"]
可以看到,這種方式同傳統(tǒng)的方式有點不同。在這種方式下,數(shù)據(jù)的表現(xiàn)形式只有一個,那就是EntityData。其好處是明顯的,不用為每個實 體都單獨編寫一個類,能夠大大減少代碼的編寫量。其缺點也很明顯,那就是不能利用編譯器類型檢測的功能,如果在調(diào)用對象的屬性的時候,寫錯了屬性的名稱, 就可能出錯,這需要更加仔細的測試工作。但是,這個問題可以通過工具生成代碼來解決。   
2 .5.數(shù)據(jù)的存取方式
數(shù)據(jù)存取的目的,是持久化保存對象,以備后來的使用,如查詢、修改、統(tǒng)計分析等。存取的對象,可以是數(shù)據(jù)庫、普通文件、XML甚至其他任何方 式,只要保證數(shù)據(jù)能夠長久保存,并且,不會受斷電、系統(tǒng)重起等因素的影響。在這個部分,最理想的狀況,自然是能夠支持除了數(shù)據(jù)庫以外的各種類型的存取方 式,或者,至少留有接口,能夠比較方便的擴充。
因為數(shù)據(jù)庫是最常用,也是最有效的數(shù)據(jù)存儲方法,因此,支持數(shù)據(jù)庫存儲是最首先必須支持的。在不同的平臺下,有不同的數(shù)據(jù)庫訪問的手段。例如, 在Java平臺下,有JDBC,在Windows平臺下,可以使用ADO、ADO.Net等。但是,這些手段還比較接近底層,在實際操縱數(shù)據(jù)庫的時候,需 要編寫大量的代碼,并且,我們還需要通過手工的方式來完成將程序中的面向?qū)ο蟮臄?shù)據(jù)存儲到關(guān)系型數(shù)據(jù)庫的工作。這么做,自然編程的效率不高,并且非常容易 出錯。但是,不可否認,這也是一種可以選用的方式。
從另外一個方面來看,由于我們前面已經(jīng)解決了數(shù)據(jù)的映射問題,因此,在數(shù)據(jù)的存取方面是非常有規(guī)律的,我們完全可以讓這個工作通過框架來執(zhí)行。 這樣,我們一方面可以簡化很多同數(shù)據(jù)庫交互方面的代碼編寫工作量,能夠減少出現(xiàn)Bug的幾率,另一方面,由于框架封裝了不同數(shù)據(jù)庫之間的差異,使得我們在 編寫程序的時候,不用考慮不同數(shù)據(jù)庫之間的差異,而將這個工作交給框架去做,實現(xiàn)軟件的后臺數(shù)據(jù)庫無關(guān)性。
在這個部分,以下兩個部分的類會顯得特別重要:
  ◆對象--關(guān)系映射的分析類,能夠通過既定的方案完成對象--關(guān)系的映射,確定數(shù)據(jù)存取方案
  ◆數(shù)據(jù)庫操縱類:根據(jù)映射關(guān)系,將數(shù)據(jù)準確的存儲到數(shù)據(jù)庫中,并且封裝不同數(shù)據(jù)庫之間的差異。
  這個部分的操作過程,可以用圖(圖2.3)大概的表示如下:
圖2.3
  在J2EE中,這個部分比較典型的就是EntityBean中的CMP。由于在BMP中,同數(shù)據(jù)庫的交互部分需要通過手工編寫代碼的方式來 實現(xiàn),因此,很難享受到容器帶來的便利,只是由于EJB2.0以前的標準,CMP的功能,包括映射能力、實體關(guān)系模式等方面的功能比較弱,所以,在很多時 候,我們不得不使用BMP。現(xiàn)在,EJB2.0,在這個方面的功能已經(jīng)非常強大了,我們完全可以享受容器帶來的便利,而將大部分精力放在實現(xiàn)更加復(fù)雜的業(yè) 務(wù)邏輯方面了。
在JDO中,您同樣可以通過PersistenceManager來實現(xiàn)同樣的目標,例如,您想把一個Customer對象保存到數(shù)據(jù)庫中,可以采用類似于下面的代碼:
Schdule schdule=new Schdule(……);
PersistenceManager PM=PMFactory.initialize(……);
Pm.persist(schdule);
代碼同樣非常簡明和直觀,沒有一大堆數(shù)據(jù)庫操縱的代碼,也不容易發(fā)生差錯。
Websharp的方案
同JDO類似,Websharp定義了PersistenceManager接口,這個接口的定義在后面的章節(jié)中會給出,這里,我們先看看其使用方式。
當我們有了某個實體對象后,需要保存到數(shù)據(jù)庫中的時候,我們可以使用下面的代碼來實現(xiàn):
public bool AddSchdule(Schdule schdule)
{
PersistenceManager pm =
PersistenceManagerFactory.Instance().CreatePersistenceManager();
try
{
pm.PersistNewObject(schdule);
return true;
}
catch
{
return false;
}
finally
{
pm.Close();
}
}
在這里,我們不需要關(guān)心具體的數(shù)據(jù)庫版本,框架會封裝不同數(shù)據(jù)庫之間的差異,保證數(shù)據(jù)可以正確的存儲到不同的數(shù)據(jù)庫中。
  在這個部分,另外需要注意的是,為了保證數(shù)據(jù)存儲的完整性,應(yīng)當考慮事務(wù)處理的功能。J2EE、JDO和Websharp都支持在數(shù)據(jù)存儲的時候使用事務(wù)處理。
在Websharp中,通過Transaction接口,提供了基本的事務(wù)處理能力。上面的代碼,如果需要使用事務(wù)處理,則可以修正如下:
public bool AddSchdule(Schdule schdule)
{
if(!CheckSchdule(schdule))
return false;
PersistenceManager pm =
PersistenceManagerFactory.Instance().CreatePersistenceManager();
Transaction trans = pm.CurrentTransaction;
trans.Begin();
try
{
pm.PersistNewObject(schdule);
trans.Commit();
return true;
}
catch
{
trans.Rollback();
return false;
}
finally
{
pm.Close();
}
}
關(guān)于事務(wù)處理的Transaction接口的更多內(nèi)容,在后面的章節(jié)中會詳細說明。
2 .6.業(yè)務(wù)邏輯的處理
  有了上面的工作,我們就可以把這些對象組合起來,編寫我們的業(yè)務(wù)邏輯。在面向?qū)ο蟮南到y(tǒng)中,業(yè)務(wù)邏輯表現(xiàn)為對象之間的交互。在一些簡單的系統(tǒng)中,沒有復(fù)雜的業(yè)務(wù)邏輯,只是一些數(shù)據(jù)的維護工作,那么,有了上面兩個部分的工作,我們實際上可能已經(jīng)忘成了大部分的工作。
  在這個部分,由于不同系統(tǒng)之間業(yè)務(wù)邏輯千差萬別,基本上沒有辦法提供統(tǒng)一的模式。但是,應(yīng)當注意的是,在同一個系統(tǒng)中,采用基本一致的策略是非常必要的,這有助于消除項目內(nèi)部的不一致性,使項目更加可控。甚至于,這些策略可以擴展成公司部分、甚至所有項目的策略。
  值得指出的是,很多人在這個部分操縱數(shù)據(jù)庫,把業(yè)務(wù)邏輯處理等同于數(shù)據(jù)庫操作,這是不可取的。在業(yè)務(wù)邏輯處理中,處理的應(yīng)該是對象,而不是直接同數(shù)據(jù)庫打交道,這樣,才能獲得更好的系統(tǒng)結(jié)構(gòu)。
  在業(yè)務(wù)邏輯處理部分,由框架提供一些支撐的服務(wù)是非常必要的。這其中,最重要的一點就是事務(wù)的處理。業(yè)務(wù)邏輯的處理過程,會涉及到多個對象之間的交互,以及多次同數(shù)據(jù)庫的交互。為了保證處理過程的完整性,必須使用事務(wù)處理的方法。框架必須支持事務(wù)處理。
  事務(wù)處理的功能,基本上有兩種選擇:使用基于數(shù)據(jù)庫連接的事務(wù)、使用外部事物處理服務(wù)[12]。
  使用基于數(shù)據(jù)庫連接的事務(wù),事務(wù)處理的性能相對比較高,但是,當系統(tǒng)涉及到多個數(shù)據(jù)庫之間的交互時,基于數(shù)據(jù)庫連接的事務(wù)便無能為力了。而使用專用的事務(wù)處理服務(wù),能夠適應(yīng)更多的情況,并且,有測試表明,隨著數(shù)據(jù)處理量的上升,兩者之間的性能差異會逐漸減小。
  在J2EE中,容器提供了事務(wù)處理的能力。在.Net平臺上,事務(wù)處理是通過Windows COM+服務(wù)來提供的。在Websharp中,如上面所講,通過Transaction接口,提供了基本的事務(wù)處理能力,能夠滿足大部分事務(wù)處理的要求。 當Websharp提供的事務(wù)處理能力不能滿足需求的時候,可以使用EnterpriseService。
  下面是一個簡單的例子:
public bool AddSchdule(Schdule schdule,string[] otherPeoples)
{
if(!CheckSchdule(schdule))
return false;
PersistenceManager pm =
PersistenceManagerFactory.Instance().CreatePersistenceManager();
Transaction trans = pm.CurrentTransaction;
trans.Begin();
try
{
pm.PersistNewObject(schdule);
foreach(string otherPeople in otherPeoples)
{
Schdule s = EntityManager.CreateObject(typeof(Schdule)) as Schdule;
s.GUID = Guid.NewGuid().ToString();
s.UserID = otherPeople;
s.StartTime = schdule.StartTime;
s.EndTime = schdule.StartTime;
s.Title = schdule.Title;
s.Description = schdule.Description;
s.RemidTime = schdule.RemidTime;
s.AddTime = DateTime.Now;
s.Status = 0;
pm.PersistNewObject(s);
}
trans.Commit();
return true;
}
catch
{
trans.Rollback();
return false;
}
finally
{
pm.Close();
}
}
在業(yè)務(wù)邏輯這一層,另外一個需要關(guān)注的問題是所謂的AOP。關(guān)于AOP的內(nèi)容,我們會在下面的章節(jié)中再討論。
2 .7.業(yè)務(wù)服務(wù)的提供
  業(yè)務(wù)外觀層(Business Facade)的目的,是隔離系統(tǒng)功能的提供者和使用者,更明確地說,是隔離業(yè)務(wù)邏輯的軟件的用戶界面(可以參見Facade設(shè)計模式)。這一層沒有任何 需要處理的邏輯,只是作為后臺邏輯處理和前端用戶界面的緩沖區(qū),以達到如下目的
  ◆將用戶界面和系統(tǒng)業(yè)務(wù)邏輯處理分開,這樣,當業(yè)務(wù)邏輯發(fā)生變化時,不用修改客戶端程序,是一種支持變化的設(shè)計方法。
  ◆使同一個業(yè)務(wù)邏輯能夠處理不同的客戶端請求。例如,可以將Facade設(shè)計成Web Service,這樣,可以同時為傳統(tǒng)的WinForm客戶端程序、Web程序以及其他外部系統(tǒng)提供服務(wù),而使用相同的應(yīng)用服務(wù)層,同時,也可以實現(xiàn)系統(tǒng) 的分布式部署。關(guān)于如何做到這一點,可以參見Ioffice的Demo程序。
  ◆作為系統(tǒng)不同模塊之間的調(diào)用接口。一個系統(tǒng)通常會包含很多模塊,這些模塊相對獨立,又可能互相調(diào)用。為了減少各個不同部分之間的耦合度,必須采用一定的設(shè)計方法,F(xiàn)acade設(shè)計模式就是非常有效的一種,也是業(yè)務(wù)外觀層的基礎(chǔ)。
  ◆有利于項目團隊的分工協(xié)作。業(yè)務(wù)外觀層作為一個訪問接口,將界面設(shè)計人員和邏輯設(shè)計人員分開,使得系統(tǒng)的開發(fā)可以實現(xiàn)縱向的分工,不同的開發(fā)人員可以關(guān)注自己的領(lǐng)域而不會受到干擾。
  業(yè)務(wù)外觀層的代碼框架,在系統(tǒng)分析和設(shè)計完成后就可以完成,他需要提供的方法,就相當于在界面設(shè)計人員和邏輯設(shè)計人員之間簽訂了一個協(xié)議, 他雖然沒有實現(xiàn)任何邏輯,但是,他的引入,能使系統(tǒng)的開發(fā)更加有條理,更加簡明。套用《設(shè)計模式》上的一句話,就是,“任何問題,都可以通過引入一個中間 層來得到簡化”。
2 .8.層的部署和層間交互
對于一個多層的應(yīng)用軟件系統(tǒng)來說,尤其是大型的應(yīng)用軟件系統(tǒng),通常需要把不同的部分部署在不同的邏輯或物理設(shè)備上。特別是一些基于Web的應(yīng)用軟件系統(tǒng), 其部署工作將涉及到Web服務(wù)器、組件服務(wù)器、數(shù)據(jù)庫服務(wù)器等不同的服務(wù)設(shè)備。在進行應(yīng)用軟件架構(gòu)的設(shè)計的時候,必須考慮各種不同的部署方案。
已經(jīng)有了很多可以用于遠程訪問的服務(wù),如此多的實現(xiàn)技術(shù),帶來的很大的靈活性,但同時也帶來了文題,其中一個就是,有多少種服務(wù)端技術(shù),就得有 多少種相應(yīng)的客戶端訪問技術(shù)。甚至,在某些分布式應(yīng)用系統(tǒng)中,應(yīng)用邏輯使用不同的技術(shù)開發(fā),存在于不同的機器上,有的存在于客戶機本機,有的使用.Net Remoting開發(fā),存在于局域網(wǎng)內(nèi),有的使用因特網(wǎng)上的Web Service,有的時候,我們希望相同的業(yè)務(wù)邏輯能夠支持不同的客戶端。
在這種情況下,我們需要一個一致的服務(wù)訪問編程模型,以統(tǒng)合不同的服務(wù)訪問模式,簡化系統(tǒng)的開發(fā)和部署。Websharp中的Service Locator提供了這樣一種能力,開發(fā)人員只需要定義服務(wù)訪問接口,就可以使用一致的方式透明的訪問這些服務(wù),而不用理會這些服務(wù)之間的不同點。框架會 自動生成訪問遠程服務(wù)需要的代理。
使用WSL,你可以使用類似于如下的代碼來訪問遠程服務(wù),而不用關(guān)心遠程服務(wù)的種類:
public interface ISecuritySystem
{
bool Login(string userID,string password);
void Logout();
bool IsLogin();
Suser CurrentUser();
}
……
//在需要調(diào)用服務(wù)的客戶端:
ISecuritySystem ss = ServiceLocator.FindService(
"SecurityService",typeof(ISecuritySystem)) as ISecuritySystem;
關(guān)于WSL的更多內(nèi)容,在后面會更加詳細的討論。
2 .9.剪裁和取舍
  以上四個層次,對于大型的應(yīng)用軟件系統(tǒng)來說,是非常必要的。但是,對于一些小型的應(yīng)用軟件系統(tǒng),如果完全按照以上的層次來做,可能反而會影響工作效率。因此,針對不同的系統(tǒng),可以對架構(gòu)進行一定的剪裁。
  數(shù)據(jù)實體層和實體控制層,是每個應(yīng)用軟件系統(tǒng)所必需的,顯然無法裁減。對于業(yè)務(wù)邏輯層和業(yè)務(wù)外觀層,根據(jù)實體情況,可以進行如下裁減:
  ◆如果系統(tǒng)沒有復(fù)雜的業(yè)務(wù)邏輯,而只是一些數(shù)據(jù)的操作,或者業(yè)務(wù)邏輯特別少,那么,可以省略業(yè)務(wù)邏輯層,而將相關(guān)的功能移至實體控制層。
  ◆如果不考慮多種客戶端的情況,也不考慮分布式部署的問題,系統(tǒng)的模塊又很少,不會產(chǎn)生模塊間緊耦合的情況,那么,可以不使用業(yè)務(wù)外觀層,而讓用戶界面程序直接訪問業(yè)務(wù)功能。
  在上面的論述中,對于每個層次,都說明了可以選擇的多種方案,每一種方案都有他的優(yōu)點和缺點,在具體開發(fā)的過程中,需要根據(jù)具體情況加以取舍。
2 .10.小結(jié)
  應(yīng)用軟件系統(tǒng)架構(gòu),是軟件工程的重要組成部分。設(shè)計一個好的框架,其目的很明確,那就是,在目前還沒有"銀彈"之前,盡最大的可能,提高軟件開發(fā)的效率和軟件質(zhì)量,把不必要的工作和容易出錯的工作,交給框架去處理。
  應(yīng)用服務(wù)層,在軟件系統(tǒng)中,是一個非常復(fù)雜的部分,乍看之下,沒有任何規(guī)律可行,給人無從下手的感覺。我們的目標,就是盡量化無規(guī)律為有規(guī) 律,把有規(guī)律的東西提取出來,形成規(guī)范,從而減少今后的開發(fā)工作量。其方法,就是對系統(tǒng)進行合理的分層,這樣,系統(tǒng)的層次清晰了,每個層次完成的功能就比 較單一,就意味著每個層次的都相對更有規(guī)律可循,這樣,我們就可以把這些有規(guī)律的東西交給框架去執(zhí)行,或者,開發(fā)一個輔助工具,來完成這部分的代碼編寫工 作。Websharp就提供了這樣一個代碼自動生成的工具。這個工具被設(shè)計成Visual Studio.Net集成開發(fā)環(huán)境的插件,在實際開發(fā)過程中,能夠提供很多便利。這是系統(tǒng)層次清晰帶來的另外一個好處。
對于一個軟件公司來說,統(tǒng)一的系統(tǒng)框架的意義不僅僅在于軟件開發(fā)的本身。一個統(tǒng)一的系統(tǒng)框架,也是公司知識管理的重要組成部分。公司如果有一個 或有限個數(shù)的明確的軟件框架,那么,這些框架就可以成為凝結(jié)公司開發(fā)人員經(jīng)驗、智慧的載體,并且可以在不斷的實踐中加以充實和完善。由于公司的軟件系統(tǒng)的 框架比較統(tǒng)一,那么當某個項目更換或增加開發(fā)人員的時候,后來的人也能夠比較容易接手,這對于公司的開發(fā)管理是具有非常重要的意義的。

第二部分 應(yīng)用服務(wù)層的設(shè)計

數(shù)據(jù)和對象
3 .1數(shù)據(jù)的形態(tài)
在應(yīng)用軟件系統(tǒng)中,首先要處理的對一個對象就是數(shù)據(jù)。應(yīng)用軟件系統(tǒng),主要目標就是采集數(shù)據(jù)、處理數(shù)據(jù)、分析數(shù)據(jù)、察看數(shù)據(jù)。對于軟件,誠如有一句名言所說:“軟件,就是數(shù)據(jù)結(jié)構(gòu)加算法”。
在軟件中,數(shù)據(jù)有多種表現(xiàn)形態(tài)。
首先,在程序中,數(shù)據(jù)總是以某種數(shù)據(jù)結(jié)構(gòu)的方式被表示出來,這種表示,通常被編譯成二進制文件存在于硬盤上,并且在運行時刻在內(nèi)存中被實例化。
這種數(shù)據(jù)結(jié)構(gòu)有多種表達的方式,簡單的情況下,他可能只是一個數(shù)字,或者一個字符串,用某個變量來描述。例如,為了表述某種商品的價格,可能使用如下的申明來表述這個數(shù)據(jù):
double price = 100 ;
現(xiàn)實中要處理的數(shù)據(jù)總是比較復(fù)雜的,為了描述一個完整的信息,通常要組合多項簡單的數(shù)據(jù),例如,為了描述某種商品的信息,通常需要描述他的名稱、價格、重量等。在傳統(tǒng)的C語言中,可以使用結(jié)構(gòu)來描述:
struct product
{
char* name;
double price;
double weight;
}
在面向?qū)ο蟮恼Z言里,類似的數(shù)據(jù)結(jié)構(gòu),可以使用類來表述。上面的代碼可以用Java語言表述如下:
public class Product
{
public String name;
public double price;
public double weight;
}
可以看出來,實際上兩者的差別是非常小的。
對于更加復(fù)雜的數(shù)據(jù)結(jié)構(gòu),一個類可能引用到其它的類,例如,上面的Product,可能有一個Size屬性,而這個Size屬性,也有height和width構(gòu)成,那么,整體的數(shù)據(jù)結(jié)構(gòu)就可以描述如下:
public class Product
{
public String name;
public double price;
public double weight;
public Size size;
}
public class Size
{
public int height;
public int width;
}
數(shù)據(jù)的另外一種表現(xiàn)形態(tài),就是永久化保存的形態(tài)。上面描述的數(shù)據(jù)的形態(tài),是一種“瞬時”的數(shù)據(jù),只有在程序運行的時候才存在于內(nèi)存中,一旦程序結(jié)束,或者數(shù)據(jù)處理結(jié)束,數(shù)據(jù)就從內(nèi)存中清楚。在很多情況下,需要把處理的數(shù)據(jù)保存到磁盤上,這時候,數(shù)據(jù)就進入永久化保存狀態(tài)。
可以有多種保存數(shù)據(jù)的格式。可以把數(shù)據(jù)保存為普通文本文件存放在磁盤上,或者,也可把數(shù)據(jù)保存在XML文件中。在Java和C#中,也都提供了這樣一種能力,就是可以把對象序列化后保存到磁盤上,然后,在需要的時候,可以反序列化成對象。
雖然有多種持久化保存數(shù)據(jù)的方案,然而其中使用關(guān)系型數(shù)據(jù)庫來保存數(shù)據(jù),無疑是最常用的辦法和最可靠的辦法。這就引伸出一個在面向?qū)ο蟮南到y(tǒng)設(shè)計中的常見問題:對象/關(guān)系型映射(O/R Mapping)。
在考慮O/R Mapping的時候,有兩個概念是經(jīng)常會接觸的,那就是VO和PO
所謂的VO,就是Value Object,這種對象,只包含了對象的數(shù)據(jù),而沒有狀態(tài),或者說,處于瞬時狀態(tài)。VO可以用來在層之間傳遞數(shù)據(jù)
所謂PO,就是Persistent Object,就是持久化保存的對象,這種對象,一般是有狀態(tài)的。O/R Mapping框架需要根據(jù)PO的狀態(tài),來執(zhí)行相應(yīng)的同數(shù)據(jù)庫的交互。關(guān)于PO的狀態(tài),我們在后面再討論
3 .2對象/關(guān)系型映射
對象關(guān)系型映射,最核心的要完成兩個功能:對象和關(guān)系型之間的映射規(guī)則,以及兩者之間的相互轉(zhuǎn)換。
除了這兩個基本的功能,一般的O/R Mapping產(chǎn)品還會加上一些額外的特性和功能,以加強產(chǎn)品的功能,為軟件開發(fā)提供更多的方便和提高性能。一些常見的功能,例如緩存。
現(xiàn)在有一些典型的O/R Mapping框架可以參考和使用,比較著名的有EJB中的Entity Bean,JDO,Hibernate等,這些方案都是基于Java的。在Microsoft.Net平臺下,相對來說可供選擇的方案比較少,其中有一個 開放源代碼的方案Websharp,可以從 www.websharp.org 下載。
我們在實際開發(fā)中,可以選擇使用已有的解決方案和產(chǎn)品,也可以自己設(shè)計自己的O/R Mapping框架。當然,無論采用何種方式,都需要我們對O/R Mapping的基本原理和方法有一個基本的了解。
在支持OO的語言中,繼承是語言的基本特征。O/R Mapping的框架,也需要對繼承做出相應(yīng)的支持。一般說來,有三種繼承模式:ONE_INHERITANCE_TREE_ONE_TABLE、 ONE_INHERITANCE_PATH_ONE_TABLE和ONE_CLASS_ONE_TABLE。
ONE_INHERITANCE_TREE_ONE_TABLE:
一個繼承樹映射到一個表,即將具有相同父類的所有類都映射到一個數(shù)據(jù)庫表中,這些類屬性映射的集合組成這個表的列,在這種模式下,只需要對最底層的類進行映射。
如下面一個類結(jié)構(gòu):
在這個類結(jié)構(gòu)中,父類Parent有兩個子類Child1和Child2,父類有屬性Property1和Property2,Child1新 增了一個屬性Property3,而Child2新增了另外一個屬性Property4,當采用 ONE_INHERITANCE_TREE_ONE_TABLE映射模式的時候,數(shù)據(jù)庫中只有一張表,結(jié)構(gòu)如下:
其中,Column1和Column2字段分別對應(yīng)Parent類的Property1和Property2屬性,Column3字段對應(yīng) Child1的Property3屬性,而Column4字段對應(yīng)Child2的Property4屬性。Column3對于Child2和 Column4對于Child1是沒有意義的。
采用這種映射模式,優(yōu)點是比較簡單,缺點是數(shù)據(jù)的冗余比較大。這個表要容納所有的子類的字段,很多字段只是對某個類有意義,而對于其他類則沒有意義,是純粹多余的,并且,在繼承樹中新增一個繼承節(jié)點的時候,往往導(dǎo)致表的字段的重新設(shè)計,這是一件非常麻煩的事情。
ONE_INHERITANCE_PATH_ONE_TABLE:
一個繼承路徑映射到一個表,即將一個類映射到一個數(shù)據(jù)庫表中,這個類的所有屬性(包括從父類繼承來的)映射的集合組成這個表的列。
在這種模式下,對于上面的類結(jié)構(gòu),數(shù)據(jù)庫的結(jié)構(gòu)就是:
其中,表Child1和Child2分別對應(yīng)于類Child1和Child2。
這種模式是非常常用的,也沒有數(shù)據(jù)冗余,缺點是在搜索的時候比較麻煩。例如,當我要搜索符合某個條件的Parent對象的時候,需要同時搜索 Child1和Child2表,并且,當在繼承樹中新增一個繼承節(jié)點的時候,需要新增一個表,搜索的范圍也必須擴大,原來的程序可能不得不重新設(shè)計。
ONE_CLASS_ONE_TABLE:
一個類映射到一個表,即將每個類映射到對應(yīng)的一個表,這個類的屬性(不包括從父類繼承來的非主鍵屬性)映射組成這個表的列,在這種模式下,具有繼承關(guān)系的類被映射到不同的表中,表之間通過主鍵關(guān)聯(lián)。
在這種模式下,對于上面的類結(jié)構(gòu),數(shù)據(jù)庫的結(jié)構(gòu)就是:
表Parent作為Child1和Child2的父表,父子表之間通過主鍵Colimn1關(guān)聯(lián)。
這種模式是非常容易理解的,因為和類圖非常相像,缺點是在查詢的時候,由于設(shè)計到表的關(guān)聯(lián),SQL語句會比較復(fù)雜,效率也會比較低。這個情況當繼承數(shù)的深度增加的時候,會體現(xiàn)的比較明顯。
如果一個類沒有子類和父類,那么采用三種模式中的哪一種都是一樣的效果。
3 .3對象的狀態(tài)
為了很好的控制對象,以及在同后臺存儲交互時的行為,通常O/R Mapping框架需要維護PO對象的狀態(tài)。在不同的框架中,對對象狀態(tài)的定義不盡相同,不過,也都有一些共同點,某些方面可能只是名稱的不同。通常的 O/R Mapping框架都需要以各種方式來直接或間接的處理PO的
分享到:
評論

構(gòu)建面向?qū)ο蟮膽?yīng)用軟件系統(tǒng)框架


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 遂昌县| 巫山县| 中卫市| 赤城县| 滁州市| 海阳市| 哈尔滨市| 平湖市| 平遥县| 隆化县| 家居| 都兰县| 大埔县| 淮南市| 嘉黎县| 武胜县| 栾川县| 永清县| 福州市| 平果县| 天祝| 扎赉特旗| 蓬溪县| 雷波县| 玛沁县| 凉城县| 梨树县| 吉水县| 胶南市| 中牟县| 蓬莱市| 汤原县| 榆树市| 会宁县| 久治县| 政和县| 科技| 龙川县| 玉田县| 蓝山县| 南康市|