J2EE體系結(jié)構(gòu)設(shè)計(jì)(二)
Posted on 2005-02-17 11:29 zhoulch's blog 閱讀(180) 評(píng)論(0) 編輯 收藏 所屬分類: J2EEJ2EE體系結(jié)構(gòu)設(shè)計(jì)(二)
6、 數(shù)據(jù)訪問(wèn)對(duì)象
數(shù)據(jù)訪問(wèn)對(duì)象(data access object,DAO)模式將數(shù)據(jù)訪問(wèn)邏輯抽象為特殊的資源,也就是說(shuō)將系統(tǒng)資源的接口從其底層訪問(wèn)機(jī)制中隔離出來(lái);通過(guò)將數(shù)據(jù)訪問(wèn)的調(diào)用打包,數(shù)據(jù)訪問(wèn)對(duì)象可以促進(jìn)對(duì)于不同數(shù)據(jù)庫(kù)類型和模式的數(shù)據(jù)訪問(wèn)。
這種模式出現(xiàn)的背景在于數(shù)據(jù)訪問(wèn)的邏輯極大程度上取決于數(shù)據(jù)存儲(chǔ)的格式,比如說(shuō)關(guān)系型數(shù)據(jù)庫(kù)、面向?qū)ο髷?shù)據(jù)庫(kù)、磁盤文件等。
目前大部分的J2EE應(yīng)用程序都需要在一定程度上使用可持久性的數(shù)據(jù),而實(shí)現(xiàn)持久性數(shù)據(jù)的方法因應(yīng)用程序不同而異,并且訪問(wèn)不同存儲(chǔ)格式數(shù)據(jù)的應(yīng)用程序接口(API)也有著顯著的差別;有的時(shí)候,應(yīng)用程序還會(huì)訪問(wèn)存儲(chǔ)在不同操作平臺(tái)上的數(shù)據(jù),這使得問(wèn)題更為復(fù)雜,通常,應(yīng)用程序會(huì)使用共享的分布式組件,如實(shí)體bean來(lái)表達(dá)持久性數(shù)據(jù)。應(yīng)用程序可以使用bean管理的持久性實(shí)體bean,而在實(shí)體bean中植人數(shù)據(jù)訪問(wèn)邏輯,或者使用容器管理的持久性實(shí)體bean,從而使容器管理所有的事務(wù)和持久性細(xì)節(jié);而如果應(yīng)用程序?qū)τ跀?shù)據(jù)訪問(wèn)的需求十分簡(jiǎn)單的話,也可以采用會(huì)話bean或Servlet直接訪問(wèn)持久性存儲(chǔ)來(lái)讀取和修改數(shù)據(jù)。
一些應(yīng)用程序可以使用JDBC應(yīng)用程序接口來(lái)訪問(wèn)關(guān)系數(shù)據(jù)庫(kù)中的數(shù)據(jù),JDBC負(fù)責(zé)一般的持久性數(shù)據(jù)訪問(wèn)和管理,在J2EE應(yīng)用程序中,JDBC中可以嵌入SQL語(yǔ)句,用以訪問(wèn)關(guān)系型數(shù)據(jù)庫(kù),當(dāng)然根據(jù)數(shù)據(jù)庫(kù)類型的不同,SQL語(yǔ)句的詞法和語(yǔ)法也會(huì)有所不同;需要說(shuō)明的是,當(dāng)數(shù)據(jù)存儲(chǔ)格式不同的時(shí)候,數(shù)據(jù)訪問(wèn)邏輯的區(qū)別就更加明顯了,例如關(guān)系型數(shù)據(jù)庫(kù)、面向?qū)ο髷?shù)據(jù)庫(kù)和磁盤文件,各自數(shù)據(jù)的訪問(wèn)邏輯各有千秋,這樣一來(lái)就造成了程序代碼和數(shù)據(jù)訪問(wèn)代碼之間的依賴關(guān)系;當(dāng)程序組件,即實(shí)體bean、會(huì)話bean或servlet、JSP等需要訪問(wèn)數(shù)據(jù)源時(shí),它們會(huì)使用正確的應(yīng)用程序接口來(lái)得到連接并管理數(shù)據(jù)源,但這樣也會(huì)造成這些組件與數(shù)據(jù)源物理實(shí)現(xiàn)之間的依賴關(guān)系,從而使得應(yīng)用程序很難從一個(gè)數(shù)據(jù)存儲(chǔ)實(shí)體移植到另一個(gè)數(shù)據(jù)存儲(chǔ)實(shí)體中去;當(dāng)數(shù)據(jù)源的物理實(shí)現(xiàn)變化的時(shí)候,應(yīng)用程序也必須相應(yīng)地加以改變。
基于以上所討論的問(wèn)題,開(kāi)發(fā)人員開(kāi)始采用數(shù)據(jù)訪問(wèn)對(duì)象的方法。數(shù)據(jù)訪問(wèn)對(duì)象實(shí)際上就是包含對(duì)于所有數(shù)據(jù)訪問(wèn)邏輯的對(duì)象,并管理著對(duì)于數(shù)據(jù)源的連接,根據(jù)數(shù)據(jù)源的不同,數(shù)據(jù)訪問(wèn)對(duì)象實(shí)現(xiàn)了不同的訪問(wèn)機(jī)制,這里所說(shuō)的數(shù)據(jù)源可以是持久性存儲(chǔ)介質(zhì),如關(guān)系型數(shù)據(jù)庫(kù),也可以是外部服務(wù),如B2B的數(shù)據(jù)交換;不僅是用戶,而且包括應(yīng)用系統(tǒng)中的其他組件,也可以使用數(shù)據(jù)訪問(wèn)對(duì)象所提供的數(shù)據(jù)訪問(wèn)接口,數(shù)據(jù)訪問(wèn)對(duì)象將數(shù)據(jù)源的物理實(shí)現(xiàn)細(xì)節(jié)與其用戶完全分離開(kāi)來(lái),并且在底層數(shù)據(jù)源變化的時(shí)候,數(shù)據(jù)訪問(wèn)對(duì)象向用戶提供的接口是不會(huì)變化的;這種方法使應(yīng)用系統(tǒng)使用數(shù)據(jù)訪問(wèn)對(duì)象時(shí)可以適應(yīng)多種數(shù)據(jù)存儲(chǔ)介質(zhì),總之,數(shù)據(jù)訪問(wèn)對(duì)象就是系統(tǒng)組件和數(shù)據(jù)源中間的適配器。
圖8中的類圖表示了數(shù)據(jù)訪問(wèn)對(duì)象設(shè)計(jì)模式的參與對(duì)象和之間的調(diào)用關(guān)系,圖9是這種設(shè)計(jì)模式的序列圖。
圖8 數(shù)據(jù)訪問(wèn)對(duì)象類圖
圖9 數(shù)據(jù)訪問(wèn)對(duì)象序列圖
對(duì)于圖9序列圖中的組件加以解釋如下:
(1)業(yè)務(wù)對(duì)象(Business Object)。表示數(shù)據(jù)的用戶,它需要對(duì)于數(shù)據(jù)的訪問(wèn),一個(gè)業(yè)務(wù)對(duì)象可以用會(huì)話bean、實(shí)體bean或是其他Java程序來(lái)實(shí)現(xiàn)。
(2)數(shù)據(jù)訪問(wèn)對(duì)象(Data Access Object)。數(shù)據(jù)訪問(wèn)對(duì)象是這種模式中的主題,它提供了底層數(shù)據(jù)訪問(wèn)的對(duì)象,并將其提供給業(yè)務(wù)對(duì)象以使得后者能夠透明地訪問(wèn)數(shù)據(jù)源;同時(shí)業(yè)務(wù)對(duì)象也將數(shù)據(jù)的加載和存儲(chǔ)操作移交給數(shù)據(jù)訪問(wèn)對(duì)象處理。
(3)數(shù)據(jù)源(Data source)。這里指的是數(shù)據(jù)源的物理實(shí)現(xiàn),這個(gè)數(shù)據(jù)源可以是一個(gè)數(shù)據(jù)庫(kù),包括關(guān)系型數(shù)據(jù)庫(kù)、面向?qū)ο髷?shù)據(jù)庫(kù)或文件系統(tǒng)。
(4)傳輸對(duì)象(Transfer Object)。這里的傳輸對(duì)象指的是數(shù)據(jù)載體。數(shù)據(jù)訪問(wèn)對(duì)象可以使用傳輸對(duì)象來(lái)向用戶返回?cái)?shù)據(jù),而數(shù)據(jù)訪問(wèn)對(duì)象同樣可以從用戶那里得到傳輸對(duì)象來(lái)對(duì)數(shù)據(jù)源中的數(shù)據(jù)進(jìn)行更新。
下面給出幾種實(shí)現(xiàn)數(shù)據(jù)訪問(wèn)對(duì)象設(shè)計(jì)模式的方法。
(1)自動(dòng)數(shù)據(jù)訪問(wèn)對(duì)象代碼的生成
既然每一個(gè)業(yè)務(wù)對(duì)象都對(duì)應(yīng)于一個(gè)數(shù)據(jù)訪問(wèn)對(duì)象,那么開(kāi)發(fā)人員就可以建立業(yè)務(wù)對(duì)象、數(shù)據(jù)訪問(wèn)對(duì)象和底層實(shí)現(xiàn)的關(guān)系;一旦這種關(guān)系建立起來(lái),開(kāi)發(fā)人員就可以為所有的數(shù)據(jù)訪問(wèn)對(duì)象編寫特殊的代碼生成工具。
生成數(shù)據(jù)訪問(wèn)對(duì)象的信息通常存儲(chǔ)在一個(gè)開(kāi)發(fā)人員定義的描述文件中,如果對(duì)于數(shù)據(jù)訪問(wèn)對(duì)象的要求過(guò)于復(fù)雜,開(kāi)發(fā)人員可以考慮使用第三方工具來(lái)為關(guān)系型數(shù)據(jù)庫(kù)提供對(duì)象對(duì)關(guān)系的映射。這些工具通常是一些GUI程序,可以用來(lái)將業(yè)務(wù)對(duì)象映射為持久性的存儲(chǔ)對(duì)象,并定義中間運(yùn)作的數(shù)據(jù)訪問(wèn)對(duì)象,在映射完成的時(shí)候,這些工具可以自動(dòng)地生成代碼,并提供一些相應(yīng)的功能,如緩存結(jié)果、緩存查詢、與應(yīng)用服務(wù)器整合、與第三方產(chǎn)品整合等。
(2)數(shù)據(jù)訪問(wèn)對(duì)象代理(Factory for Data Access Objects)
當(dāng)?shù)讓拥臄?shù)據(jù)存儲(chǔ)不會(huì)輕易改變的時(shí)候,開(kāi)發(fā)人員可以采取這種方法來(lái)實(shí)現(xiàn)相應(yīng)的,數(shù)據(jù)訪問(wèn)對(duì)象,圖10是這種方法的類圖。
圖10 使用DAO代理類圖
當(dāng)?shù)讓拥臄?shù)據(jù)存儲(chǔ)可能會(huì)變化的時(shí)候,開(kāi)發(fā)人員可以采用抽象代理的方法來(lái)實(shí)現(xiàn)數(shù)據(jù)訪問(wèn)對(duì)象;抽象代理的方法會(huì)創(chuàng)建一些虛擬的數(shù)據(jù)訪問(wèn)對(duì)象代理和各種類型的實(shí)際數(shù)據(jù)訪問(wèn)對(duì)象代理,每種對(duì)象對(duì)應(yīng)一種持久性存儲(chǔ)介質(zhì)的實(shí)現(xiàn),一旦組件得到這些代理,就可以利用來(lái)創(chuàng)建需要使用的數(shù)據(jù)訪問(wèn)對(duì)象。
圖11給出了這種情況的類圖。該類圖表示了一個(gè)基礎(chǔ)的數(shù)據(jù)訪問(wèn)對(duì)象代理,它是一個(gè)抽象類,被其他一些實(shí)際的數(shù)據(jù)訪問(wèn)對(duì)象代理繼承以支持特定的數(shù)據(jù)訪問(wèn)函數(shù);用戶可以得到一個(gè)實(shí)際的數(shù)據(jù)訪問(wèn)對(duì)象,并利用它來(lái)創(chuàng)建需要的數(shù)據(jù)訪問(wèn)對(duì)象而訪問(wèn)相關(guān)的數(shù)據(jù),每一個(gè)實(shí)際的數(shù)據(jù)訪問(wèn)對(duì)象都負(fù)責(zé)建立對(duì)于數(shù)據(jù)源的連接,并得到和管理所支持的業(yè)務(wù)數(shù)據(jù)。
圖11 抽象代理使用DAO
下圖12是這種情況下的序列圖。
圖12抽象代理使用DAO序列圖
這種設(shè)計(jì)模式的優(yōu)勢(shì):
-
透明性好。業(yè)務(wù)對(duì)象可以在不知道數(shù)據(jù)源實(shí)現(xiàn)細(xì)節(jié)的情況下訪問(wèn)數(shù)據(jù)。由于一切數(shù)據(jù)訪問(wèn)細(xì)節(jié)被數(shù)據(jù)訪問(wèn)對(duì)象所隱藏,所以這種訪問(wèn)過(guò)程是透明的。
-
可移植性好。在應(yīng)用系統(tǒng)中添加數(shù)據(jù)訪問(wèn)對(duì)象,可以使得前者能夠很方便地移植到另外一種數(shù)據(jù)庫(kù)實(shí)現(xiàn)上。業(yè)務(wù)對(duì)象與數(shù)據(jù)實(shí)現(xiàn)是隔離的,所以在移植過(guò)程中,僅僅對(duì)數(shù)據(jù)訪問(wèn)對(duì)象進(jìn)行一些變化即可。
-
減少業(yè)務(wù)對(duì)象的代碼復(fù)雜度。由于數(shù)據(jù)訪問(wèn)對(duì)象可以管理所有的數(shù)據(jù)訪問(wèn)復(fù)雜細(xì)節(jié),這也就簡(jiǎn)化了業(yè)務(wù)模塊和其他數(shù)據(jù)客戶的代碼。同時(shí)也提高了應(yīng)用系統(tǒng)的整體可讀性和開(kāi)發(fā)率。
-
集中處理所有數(shù)據(jù)訪問(wèn)。由于所有的數(shù)據(jù)訪問(wèn)操作都移交給數(shù)據(jù)訪問(wèn)對(duì)象,這樣應(yīng)用系統(tǒng)其他部分就與數(shù)據(jù)訪問(wèn)實(shí)現(xiàn)隔離開(kāi)來(lái),而全部相關(guān)操作都與數(shù)據(jù)訪問(wèn)對(duì)象集中處理,這樣也使得相關(guān)操作更加容易被維護(hù)和管理。
這種設(shè)計(jì)模式的缺陷:
-
對(duì)于容器管理的持久性不能利用。如果EJB容器采取容器管理的方式,那么所有對(duì)于持久性數(shù)據(jù)存儲(chǔ)的管理都由容器負(fù)責(zé)。這樣的話應(yīng)用系統(tǒng)就無(wú)需實(shí)現(xiàn)數(shù)據(jù)訪問(wèn)對(duì)象了,因?yàn)閼?yīng)用服務(wù)將透明地提供這一功能。
-
添加了額外的層面。數(shù)據(jù)訪問(wèn)對(duì)象在數(shù)據(jù)用戶和數(shù)據(jù)源之間添加了一個(gè)層面,也就增加了一些額外的設(shè)計(jì)和實(shí)現(xiàn)的負(fù)擔(dān)。當(dāng)然,我們認(rèn)為它是物有所值的。
總之,在開(kāi)發(fā)人員選擇不同模式的時(shí)候,應(yīng)該注意,一定的模式對(duì)應(yīng)于一定的應(yīng)用層次。比如說(shuō),與視圖和顯示相關(guān)的模式就是在Web層應(yīng)用的。而一些與業(yè)務(wù)邏輯控制相關(guān)的模式則是與EJB層次相關(guān)的。另外一些關(guān)于讀取數(shù)據(jù)和分派操作的模式則適用于不同的層次之間
7、值對(duì)象或傳輸對(duì)象
值對(duì)象(value object)模式通過(guò)減少分布式通信的消息而促進(jìn)數(shù)據(jù)的交換,通常這里所指的通信是在Web層和EJB層之間。在一個(gè)遠(yuǎn)程調(diào)用中,一個(gè)單一值對(duì)象可以被用來(lái)取出一系列相關(guān)數(shù)據(jù)并提供給客戶。
這種設(shè)計(jì)模式的出現(xiàn)是基于客戶需要與ejb大量地交換數(shù)據(jù)的情況。具體來(lái)說(shuō),在J2EE平臺(tái)中,應(yīng)用系統(tǒng)通常將服務(wù)器端的程序組件實(shí)現(xiàn)為會(huì)話bean和實(shí)體bean,而這些組件的部分方法則需要將數(shù)據(jù)返回給客戶;這種情況下,通常一個(gè)用戶會(huì)重復(fù)調(diào)用相關(guān)方法多次,直到它得到相關(guān)信息,應(yīng)該注意的是,多數(shù)情況這些方法調(diào)用的目的都是為了取得單一的信息,例如用戶名或者用戶地址等。
顯而易見(jiàn),在J2EE平臺(tái)上,這種調(diào)用基本上都是來(lái)自遠(yuǎn)程的。也就是說(shuō),用戶多次調(diào)用相應(yīng)的方法會(huì)給Web帶來(lái)極大的負(fù)擔(dān),即使用戶和EJB容器加載相同的JVM、OS和計(jì)算機(jī)上運(yùn)行EJB程序,由于方法調(diào)用被缺省地認(rèn)為是遠(yuǎn)程任務(wù),所以這種問(wèn)題依然存在。
由于以上所提到的問(wèn)題,在遠(yuǎn)程方法的調(diào)用次數(shù)增加的時(shí)候,相關(guān)的應(yīng)用程序性能將會(huì)有很大的下降,因此利用多次方法調(diào)用而取得單一的信息是非常低效的;在這種情況,J2EE的研究人員建議使用傳輸對(duì)象來(lái)包含所有的程序數(shù)據(jù),即每次方法調(diào)用可以發(fā)送和接收這個(gè)傳輸對(duì)象;當(dāng)用戶向EJB發(fā)出對(duì)于程序數(shù)據(jù)的請(qǐng)求時(shí),EJB會(huì)創(chuàng)建這個(gè)傳輸對(duì)象,將它的各個(gè)域賦以相關(guān)的數(shù)值,并將整個(gè)對(duì)象傳送給用戶。
當(dāng)EJB使用傳輸對(duì)象的時(shí)候,用戶可以通過(guò)僅僅一次方法調(diào)用來(lái)取得整個(gè)對(duì)象,而不是使用多次方法調(diào)用以得到對(duì)象中每個(gè)域的數(shù)值;由于傳輸對(duì)象是通過(guò)值傳遞而交送給用戶的,所以所有對(duì)于該傳輸對(duì)象的調(diào)用或取值都是本地調(diào)用,而不是遠(yuǎn)程方法調(diào)用。不過(guò)需要注意的是,這個(gè)傳輸對(duì)象必須具有對(duì)應(yīng)于每個(gè)屬性的訪問(wèn)方法,或者將所有屬性都設(shè)為公共的。
類圖13表示了傳輸對(duì)象模式的體系結(jié)構(gòu)。
圖13 傳輸對(duì)象類圖
在圖13中,傳輸對(duì)象首先在EJB中創(chuàng)建,然后返回給遠(yuǎn)程客戶;當(dāng)然,傳輸對(duì)象也可以根據(jù)需要融合其他的設(shè)計(jì)模式。
圖14顯示了傳輸對(duì)象模式中的參與模塊和它們之間的交互。
圖14 傳輸對(duì)象序列圖
下面我們說(shuō)明一下傳輸對(duì)象模式的各個(gè)參與模塊:
(1)客戶(Client)。客戶代表了EJB所提供服務(wù)的使用者,通常是運(yùn)行于用戶終端的應(yīng)用程序。
(2)業(yè)務(wù)對(duì)象。業(yè)務(wù)對(duì)象表示在一個(gè)模式中由會(huì)話bean、實(shí)體bean或數(shù)據(jù)訪問(wèn)對(duì)象(Data Access Object)實(shí)現(xiàn)的角色。業(yè)務(wù)對(duì)象通常負(fù)責(zé)創(chuàng)建傳輸對(duì)象,并根據(jù)請(qǐng)求將其傳送到相關(guān)的用戶;業(yè)務(wù)對(duì)象也可以從用戶中取得一個(gè)傳輸對(duì)象格式的數(shù)據(jù),并應(yīng)用這些數(shù)據(jù)來(lái)執(zhí)行一些更新。
(3)傳輸對(duì)象。傳輸對(duì)象是一個(gè)可序列化的Java對(duì)象。在這個(gè)對(duì)象的類中,通常會(huì)有一個(gè)包含所有域的構(gòu)造函數(shù),用來(lái)創(chuàng)建這個(gè)傳輸對(duì)象。
這個(gè)傳輸對(duì)象中的成員變量基本都被定義為公共,從而無(wú)需為它們提供相關(guān)的訪問(wèn)方法。當(dāng)然如果存在一定安全的需要,相關(guān)的成員變量也可以設(shè)為保護(hù)或私有,并且給定各自的訪問(wèn)方法。由此可見(jiàn),傳輸對(duì)象的設(shè)計(jì)是隨著應(yīng)用系統(tǒng)的需要不同而改變的,是否將對(duì)象中的成員變量設(shè)為公共,或提供一定的訪問(wèn)方法,將是一個(gè)很重要的設(shè)計(jì)問(wèn)題。
通常在實(shí)現(xiàn)這個(gè)模式時(shí),最多采取的是可更新的傳輸對(duì)象策略和多傳輸對(duì)象策略。 在可更新的傳輸對(duì)象策略中,傳輸對(duì)象不僅可以從服務(wù)于用戶的業(yè)務(wù)對(duì)象中取得相關(guān)信息和數(shù)據(jù),還可以從業(yè)務(wù)對(duì)象中得到用戶對(duì)于數(shù)據(jù)所需要進(jìn)行的改變。
圖15以類圖表的形式表明了業(yè)務(wù)對(duì)象和傳輸對(duì)象之間的關(guān)系。
圖15 可更新傳輸對(duì)象類圖
業(yè)務(wù)對(duì)象創(chuàng)建了傳輸對(duì)象。而用戶通過(guò)訪問(wèn)業(yè)務(wù)對(duì)象,既得到了所需的信息,也對(duì)相關(guān)數(shù)據(jù)做出了一定的修改;為了能夠使得用戶可以修改業(yè)務(wù)對(duì)象各個(gè)域的取值,這個(gè)對(duì)象必須提供一定的變值方法,而出于對(duì)Web負(fù)擔(dān)的考慮,業(yè)務(wù)對(duì)象所提供的方法最好以傳輸對(duì)象為參數(shù)。相應(yīng)地,這些方法可以去調(diào)用傳輸對(duì)象所提供的方法,來(lái)設(shè)置傳輸對(duì)象的各個(gè)成員變量的取值;同時(shí)在傳輸對(duì)象的方法中,我們也可以植入數(shù)據(jù)驗(yàn)證和完整性檢查的邏輯,這樣在用戶從業(yè)務(wù)對(duì)象的方法得到傳輸對(duì)象時(shí),可以直接調(diào)用傳輸對(duì)象的成員方法進(jìn)行本地?cái)?shù)據(jù)訪問(wèn),當(dāng)然這種本地?cái)?shù)據(jù)訪問(wèn)不會(huì)影響到業(yè)務(wù)對(duì)象。
當(dāng)用戶調(diào)用業(yè)務(wù)對(duì)象的變值方法時(shí),該方法會(huì)將用戶端的傳輸對(duì)象序列化,再將它發(fā)送給業(yè)務(wù)對(duì)象;業(yè)務(wù)對(duì)象接收到更新的傳輸對(duì)象,便將這些更新寫回到自己的對(duì)象拷貝中去; 這里需要說(shuō)明的是,上面提到的寫回只是涉及到被更新的變量,而不是全部變量的寫回,因此我們需要在傳輸對(duì)象中另設(shè)置一個(gè)變量,來(lái)指定哪些成員變量被用戶更新過(guò),這也就使得這種模式的設(shè)計(jì)相對(duì)復(fù)雜,開(kāi)發(fā)人員需要考慮同步化和版本控制的問(wèn)題。
圖16顯示了這個(gè)更新過(guò)程的序列圖。
圖16 可更新傳輸對(duì)象序列圖
多傳輸對(duì)象的方法是指一個(gè)單一的業(yè)務(wù)對(duì)象可以根據(jù)用戶請(qǐng)求制造多個(gè)不同的傳輸對(duì)象。也就是說(shuō),業(yè)務(wù)對(duì)象和它所創(chuàng)建的傳輸對(duì)象保持一對(duì)多的關(guān)系。類圖17表示了這種實(shí)現(xiàn)方法的各個(gè)參與模塊以及它們之間的調(diào)用關(guān)系。
圖17 多傳輸對(duì)象類圖
當(dāng)一個(gè)用戶需要A類型的傳輸對(duì)象時(shí),他會(huì)激活相關(guān)EJB的getDataA()方法來(lái)取得傳輸對(duì)象A;當(dāng)他需要B類型的傳輸對(duì)象時(shí),他會(huì)激活getDataB()方法來(lái)獲取傳輸對(duì)象B;依此類推。序列圖18表示了這一過(guò)程。
圖18 多傳輸對(duì)象序列圖
使用這種設(shè)計(jì)模式,應(yīng)用系統(tǒng)的實(shí)體bean及其遠(yuǎn)程接口會(huì)變得十分簡(jiǎn)單。實(shí)體bean中無(wú)需再為每一個(gè)成員變量都實(shí)現(xiàn)一個(gè)set()和get()方法,并在遠(yuǎn)程接口中實(shí)現(xiàn)相應(yīng)的定義。用戶無(wú)需再進(jìn)行多次的方法調(diào)用來(lái)取得信息和數(shù)據(jù),所需要的只是一次方法調(diào)用以獲得整個(gè)傳輸對(duì)象。當(dāng)然這里需要考慮Web負(fù)擔(dān)和大量數(shù)據(jù)一次傳輸?shù)臋?quán)衡。開(kāi)發(fā)人員可以根據(jù)不同的需要來(lái)選擇不同的實(shí)現(xiàn)方法。
如上所述,用戶和實(shí)體bean之間可以通過(guò)在一次方法調(diào)用中使用傳輸對(duì)象而交換所有的數(shù)據(jù),也就是說(shuō)傳輸對(duì)象作為數(shù)據(jù)載體工作,并減少了遠(yuǎn)程的方法調(diào)用,從而大大減輕了Web負(fù)擔(dān)。通過(guò)使用傳輸對(duì)象的方法,我們也將有可能減少實(shí)體bean和其傳輸對(duì)象間的代碼重復(fù)。不過(guò)在使用可更新的傳輸對(duì)象方法時(shí),用戶可以修改其本地的傳輸對(duì)象,之后再將其傳送回業(yè)務(wù)對(duì)象中,后者將所需的更新整合到自己一端;但是這樣一來(lái),就會(huì)存在一個(gè)版本控制的問(wèn)題,不同的客戶可能在同時(shí)修改相同類型的傳輸對(duì)象,而如果相關(guān)的業(yè)務(wù)對(duì)象沒(méi)有發(fā)現(xiàn)這一點(diǎn)的話,可能就會(huì)造成一些用戶的數(shù)據(jù)沒(méi)有得到及時(shí)更新,而另外一些用戶的數(shù)據(jù)又被覆蓋的情況;在系統(tǒng)設(shè)計(jì)中必須考慮這個(gè)問(wèn)題。
8、截取過(guò)濾器
截取過(guò)濾器(intercepting filter)主要用于對(duì)于用戶請(qǐng)求的之前處理和之后處理,也就是說(shuō)它對(duì)于客戶的請(qǐng)求使用了額外的操作。比如說(shuō),servlet可以處理一個(gè)網(wǎng)站的所有客戶請(qǐng)求并提供一個(gè)核心的認(rèn)證機(jī)制。
這種模式主要工作于表示層,負(fù)責(zé)處理不同類型的請(qǐng)求,同時(shí)也需要進(jìn)行多種不同的處理。在這些請(qǐng)求中,有一些請(qǐng)求會(huì)直接傳送給后端模塊處理,而另外一些請(qǐng)求則先會(huì)在過(guò)濾器里解釋或補(bǔ)充內(nèi)容,之后才能傳送給后端模塊。這種模式的提出主要是由于一個(gè)客戶的Web訪問(wèn)和系統(tǒng)響應(yīng)都需要一定的預(yù)處理和后處理,例如用戶身份、用戶環(huán)境信息、用戶請(qǐng)求的合法性等。通常這些處理的結(jié)果都會(huì)決定用戶的請(qǐng)求是否能夠進(jìn)行,或是系統(tǒng)的響應(yīng)應(yīng)該用什么格式來(lái)表示。
對(duì)于這種預(yù)處理和后處理問(wèn)題,傳統(tǒng)上,開(kāi)發(fā)人員會(huì)設(shè)計(jì)一系列額外的檢測(cè)程序模塊,也就是一整套if/else語(yǔ)句,并且指定如果其中任何一個(gè)檢測(cè)失敗,所有的處理工作都會(huì)退出。顯然,這種方法是存在很大弊端的,即代碼的可讀性、可維護(hù)性都會(huì)被大大降低,同時(shí)將檢測(cè)工作融于一般的程序模塊,使得整個(gè)程序的模塊性難以保證。
解決這種問(wèn)題的關(guān)鍵在于,設(shè)計(jì)一種簡(jiǎn)單的技術(shù),以能夠添加或移除額外處理的模塊,而這些模塊通常都能夠完成一定的檢測(cè)和過(guò)濾功能。根據(jù)以上的討論,J2EE研究人員提出了設(shè)計(jì)模式----截取過(guò)濾器作為解決方案,這種模式可以在不影響核心處理模塊的情況下,實(shí)現(xiàn)可插入的過(guò)濾器來(lái)執(zhí)行一般的處理功能。
從理論上來(lái)說(shuō),這種過(guò)濾器可以截取客戶請(qǐng)求和系統(tǒng)響應(yīng),并進(jìn)行相應(yīng)的預(yù)處理和后處理;同時(shí)開(kāi)發(fā)人員也可以隨時(shí)根據(jù)需要移除這些過(guò)濾器,并不用擔(dān)心會(huì)改變?nèi)魏纹渌K。
我們這里所說(shuō)的預(yù)處理和后處理功能,通常是指一些基本的系統(tǒng)服務(wù),如安全、登錄,系統(tǒng)調(diào)試等。執(zhí)行這些功能的過(guò)濾器通常是需要與核心模塊分開(kāi)的,并且由于系統(tǒng)職能或規(guī)則的變化,這些模塊隨時(shí)可能被添加或刪除。
下面提供一些關(guān)于截取過(guò)濾器的圖示,以幫助大家更好地理解這種設(shè)計(jì)模式,并合理地加以運(yùn)用。圖19表示了截取過(guò)濾器模式的整體結(jié)構(gòu),圖19顯示了截取過(guò)濾器中的參與模塊和相互之間的聯(lián)系。
圖19 截取過(guò)濾器模式
圖20 截取過(guò)濾器序列圖
下面我們分別來(lái)說(shuō)明圖20中的各個(gè)模塊:
(1)過(guò)濾管理器(Filter Manager)。過(guò)濾管理器負(fù)責(zé)過(guò)濾器的主要處理工作,即創(chuàng)建過(guò)濾器鏈對(duì)象以及相應(yīng)的過(guò)濾器組建,并初始化整個(gè)處理過(guò)程。
(2)過(guò)濾器鏈(Filter Chain)。過(guò)濾器鏈?zhǔn)且唤M互不依賴的過(guò)濾器有序集合。
(3)過(guò)濾器1,過(guò)濾器2,過(guò)濾器3(FilterOne,F(xiàn)ilterTwo,F(xiàn)ilterThree)。這些都是提供不同服務(wù)的過(guò)濾器,而過(guò)濾器鏈則負(fù)責(zé)它們的協(xié)調(diào)工作。
通過(guò)采用這種設(shè)計(jì)模式,應(yīng)用系統(tǒng)可以取得更方便的中心控制,這是由于過(guò)濾器可以提供處理多種請(qǐng)求的中心模塊,并能根據(jù)后端的處理模塊而解釋和潤(rùn)色用戶的請(qǐng)求,使得該請(qǐng)求能更好地與處理模塊所提供的功能匹配。另外,過(guò)濾器通常可以將不同種類的服務(wù)聚集在一起,并提供相當(dāng)靈活的服務(wù)組合,應(yīng)用系統(tǒng)可以通過(guò)使用截取過(guò)濾器提高其重用性,過(guò)濾器可以隨時(shí)根據(jù)需要從其他程序模塊中插入或移除,并且由于它們通常具有標(biāo)準(zhǔn)的接口,開(kāi)發(fā)人員可以使用一組類似的過(guò)濾器,并在不同的情況下進(jìn)行全組的重用。
采用這種設(shè)計(jì)模式也會(huì)帶來(lái)一定的問(wèn)題,即在過(guò)濾器之間共享信息將變得非常困難,這是由于根據(jù)其定義和需求,每個(gè)過(guò)濾器的設(shè)計(jì)和開(kāi)發(fā)都大相徑庭。因而如果在不同的過(guò)濾器之間需要共享信息的話,其代價(jià)將是非常昂貴的。
作者:務(wù)實(shí),多年從事J2EE網(wǎng)站及應(yīng)用系統(tǒng)項(xiàng)目的開(kāi)發(fā)和應(yīng)用。
參考資料:
《J2EE設(shè)計(jì)開(kāi)發(fā)編程指南》 Rod Johnson 電子工業(yè)出版社
《J2EE參考大全》 Jim Keogh 電子工業(yè)出版社
《實(shí)用J2EE設(shè)計(jì)模式編程指南》 Craig A.Berry 電子工業(yè)出版社