目前大多數企業(yè)采用J2EE技術(shù)的結構設計與解決方案。對于我們學(xué)習和研究J2EE體系結構來(lái)說(shuō),了解與掌握J2EE體系結構的設計方法及一些常用模式是必須的;模型-視圖-控制(model-view-control,簡(jiǎn)稱(chēng)MVC)結構是目前最常見(jiàn)的J2EE應用所基于的體系結構,MVC主要適用于交互式的Web應用,尤其是存在大量頁(yè)面及多次客戶(hù)訪(fǎng)問(wèn)及數據顯示;相比較而言,一個(gè)工作流體系結構更多應用于過(guò)程控制和較少交互的情況下;除了體系結構外,J2EE的設計模式對我們解決應用系統的設計也有很大的幫助。
一、J2EE的模型-視圖-控制(MVC)體系結構
模型-視圖-控制結構是交互式應用程序廣泛使用的一種體系結構。它有效地在存儲和展示數據的對象中區分功能模塊以降低它們之間的連接度,這種體系結構將傳統的輸入、處理和輸入模型轉化為圖形顯示的用戶(hù)交互模型,或者換一種說(shuō)法,是多層次的Web商業(yè)應用;MVC體系結構具有三個(gè)層面:模型(Model)、視圖(View)和控制(Controller),每個(gè)層面有其各自的功能作用,MVC體系結構如下:
圖1 MVC 體系結構
模型層負責表達和訪(fǎng)問(wèn)商業(yè)數據,執行商業(yè)邏輯和操作。也就是說(shuō),這一層就是現實(shí)生活中功能的軟件模擬;在模型層變化的時(shí)候,它將通知視圖層并提供后者訪(fǎng)問(wèn)自身狀態(tài)的能力,同時(shí)控制層也可以訪(fǎng)問(wèn)其功能函數以完成相關(guān)的任務(wù)。
視圖層負責顯示模型層的內容。它從模型層取得數據并指定這些數據如何被顯示出來(lái)。在模型層變化的時(shí)候,它將自動(dòng)更新。另外視圖層也會(huì )將用戶(hù)的輸入傳送給控制器。
控制層負責定義應用程序的行為。它可以分派用戶(hù)的請求并選擇恰當的視圖以用于顯示,同時(shí)它也可以解釋用戶(hù)的輸入并將它們映射為模型層可執行的操作;在一個(gè)圖形界面中,常見(jiàn)的用戶(hù)輸入包括點(diǎn)擊按鈕和菜單選擇。在Web應用中,它包括對Web層的HTTP GET和POST的請求;控制層可以基于用戶(hù)的交互和模型層的操作結果來(lái)選擇下一個(gè)可以顯示的視圖,一個(gè)應用程序通常會(huì )基于一組相關(guān)功能設定一個(gè)控制層的模塊,甚至一些應用程序會(huì )根據不同的用戶(hù)類(lèi)型具有不同的控制層設定,這主要是由于不同用戶(hù)的視圖交互和選擇也是不同的。
在模型層、視圖層和控制層之間劃分責任可以減少代碼的重復度,并使應用程序維護起來(lái)更簡(jiǎn)單。同時(shí)由于數據和商務(wù)邏輯的分開(kāi),在新的數據源加入和數據顯示變化的時(shí)候,數據處理也會(huì )變得更簡(jiǎn)單。
二、J2EE設計模式
一個(gè)設計模式描述了對于特定設計問(wèn)題被驗證的解決方案,它綜合了所有開(kāi)發(fā)者對這個(gè)問(wèn)題所在領(lǐng)域的知識和見(jiàn)解;同時(shí)也是對于常見(jiàn)問(wèn)題的可重用方案,它們一般適用于單個(gè)問(wèn)題,但是組織在一起就可以提供整個(gè)企業(yè)系統的解決方案。下面我們列舉八種常用于J2EE平臺的設計模式,并對每種模式作簡(jiǎn)單的介紹,便于大家學(xué)習、理解與靈活應用。
1、前控制器
前控制器(front controller)主要提供一種可以集中式管理請求的控制器,一個(gè)前控制器可以接受所有的客戶(hù)請求,將每個(gè)請求遞交給相應的請求句柄,并適當地響應用戶(hù)。
前控制器也是表示層的設計模式,它的出現主要是由于表示層通常需要控制和協(xié)調來(lái)自不同用戶(hù)的多個(gè)請求,而這種控制機制又根據不同的需要,可能會(huì )集中式控制或分散式控制。換句話(huà)說(shuō),就是應用系統需要對于表示層的請求提供一個(gè)集中式控制模塊,以提供各種系統服務(wù),包括內容提取、視圖管理和瀏覽,如果系統中沒(méi)有這種集中式控制模塊或控制機制,每個(gè)不同的系統服務(wù)都需要進(jìn)行單獨的視圖處理,這樣代碼的重復性就會(huì )提高,致使系統開(kāi)發(fā)代價(jià)提高;同時(shí),如果沒(méi)有一個(gè)固定模塊管理視圖之間的瀏覽機制,致使其瀏覽功能下放于每個(gè)不同的視圖中,最終必將使得系統的可維護性受到破壞;本文中我們主要討論的是集中式控制模塊,而不是分散式控制,因為前者更適合于大型的應用系統。
基于上面所說(shuō)的問(wèn)題,研究人員提出了前控制器的設計模式。在這種模式中,控制器提供一個(gè)處理不同請求的控制點(diǎn),這里的處理工作包括安全事務(wù)、視圖選擇、錯誤處理和響應內容的生成;通過(guò)將這些處理工作集中在一點(diǎn)進(jìn)行,大大地減低了Java代碼量,同時(shí)這種方法也可以減少在視圖模塊的程序邏輯,保證了在不同請求之間可以重用大量的邏輯代碼。通常,控制器都是和一個(gè)分派組件聯(lián)合工作的,分派組件主要是用于視圖管理和瀏覽,也就是為用戶(hù)選擇下一個(gè)應該顯示的視圖,并同時(shí)提供對于相關(guān)顯示資源的控制。分派組件可以包含在控制器之內,或是在另外一個(gè)單獨的組件中;雖然前控制器模式推薦對于全部的請求使用統一處理,但是它也沒(méi)有限制在一個(gè)系統中只能具有一個(gè)控制器,在系統中的每個(gè)層次都可以具有多個(gè)控制器,并且映射至不同的系統服務(wù),下圖2顯示了前控制器的類(lèi)圖。
圖2 前控制器的類(lèi)圖
圖3顯示了前控制器的序列圖,表示一個(gè)控制器如何處理相關(guān)的請求。
圖3前控制器序列圖
下面我們來(lái)討論一下圖3的各個(gè)組件。
2、控制器
控制器(controller)是負責處理各種客戶(hù)請求的控制點(diǎn),并可以將一定的職能(如用戶(hù)認證等)下放給幫助類(lèi)。
(1)分派組件(Dispatcher)。一個(gè)分派組件主要是用于視圖的管理和瀏覽,為用戶(hù)選擇下一個(gè)可以顯示的視圖,并管理相關(guān)的顯示資源;分派組件可以在一個(gè)控制器內運行,或者作為一個(gè)單獨的組件與控制器協(xié)同工作;開(kāi)發(fā)人員可以在分派組件中實(shí)現靜態(tài)的視圖分派技術(shù),或是復雜的動(dòng)態(tài)分派。
(2)幫助類(lèi)(Helper)。幫助類(lèi)負責幫助一個(gè)視圖或控制器來(lái)完成其處理工作,因此,幫助類(lèi)具有多項職責,包括收集數據、存儲中間數據模型等;另外,幫助類(lèi)也可以在保證數據完整性和準確性的情況下,為不同顯示需求修改數據模型;也就是說(shuō),根據用戶(hù)的請求,幫助類(lèi)可以向視圖提供未經(jīng)處理的原始數據,或是已經(jīng)格式化后的Web內容,一個(gè)視圖同時(shí)可以和多個(gè)幫助類(lèi)協(xié)同工作,而后者通常是由JavaBeans和標簽(tag)實(shí)現的。
3、視圖
視圖(view)負責向用戶(hù)顯示信息,而幫助類(lèi)則負責支持視圖的工作,即打包和建立相應的數據模型,下面我們介紹幾種可以實(shí)現控制器的方法。
1)基于Servlet前控制器
這種方法建議使用servlet來(lái)實(shí)現一個(gè)控制器,盡管在語(yǔ)法上相差無(wú)幾,但是它比使用JSP來(lái)實(shí)現要優(yōu)越一些;因為控制器所進(jìn)行的請求處理,多數都是與程序運行和控制流動(dòng)相關(guān)的,這些處理工作雖然與顯示模式相關(guān),但是實(shí)際上是邏輯獨立的,所以它們更適合在servlet中實(shí)現,而不是JSP技術(shù)中;使用這種方法也存在一些弱點(diǎn),比如說(shuō)servlet無(wú)法使用JSP運行環(huán)境的資源,如請求參數等,但是這個(gè)弱點(diǎn)也不是不能解決的,我們可以在servlet中建立相關(guān)的句柄來(lái)訪(fǎng)問(wèn)同樣的資源,當然其代碼會(huì )變得繁瑣一點(diǎn)。
2)基于JSP的前控制器
這種方法建議使用JSP頁(yè)面實(shí)現控制器,盡管語(yǔ)法上相同,但是Servlet方案要比其優(yōu)越一些;因為控制器所處理的邏輯一般都不是有關(guān)顯示模式的,所以在JSP頁(yè)面中實(shí)現控制器似乎有點(diǎn)風(fēng)馬牛不相及;使用這種方法也不利于開(kāi)發(fā)團隊的角色和職責的分配,即軟件開(kāi)發(fā)人員需要在負責顯示邏輯的JSP頁(yè)面中修改請求處理的代碼,通常,這種工作都是相當復雜的,尤其考慮整個(gè)JSP頁(yè)面的編程、編譯、測試和調試錯誤。
3)控制器之中的分派組件
如果分派組件沒(méi)有較多功能,開(kāi)發(fā)人員可以在控制器實(shí)現該組件。
4)基礎前端
基于使用servlet實(shí)現前控制器,這種方案建議實(shí)現一個(gè)控制器作為基礎類(lèi),這樣其他的控制器可以在其之上擴展;這個(gè)基礎類(lèi)可以包含一些通用的邏輯實(shí)現,它的子類(lèi)就會(huì )重載這些實(shí)現代碼,這種方法也有一定的缺陷,當有許多子類(lèi)繼承這個(gè)基礎類(lèi),并大量地重用代碼時(shí),那么就有可能出現一個(gè)類(lèi)的改變會(huì )影響到所有子類(lèi)的情況。
5)用過(guò)濾器實(shí)現前控制器
過(guò)濾器提供了與用戶(hù)請求的中心處理相類(lèi)似的功能,也就是說(shuō),控制器的一些功能可以由過(guò)濾器來(lái)實(shí)現,這種方案的過(guò)濾器主要負責處理請求的截取和解釋?zhuān)皇钦埱蟮奶幚砗晚憫纳?;通??梢詾閼孟到y提供一個(gè)核心控制點(diǎn),以處理所有的系統服務(wù)和程序邏輯,核心控制也就表明了所有的請求都可以簡(jiǎn)單地被跟蹤和記錄,從而方便各種服務(wù)功能的實(shí)施;當然,它也存在一些缺點(diǎn),一個(gè)核心控制點(diǎn)的小問(wèn)題可能會(huì )引發(fā)系統的崩潰,但在應用系統的實(shí)際開(kāi)發(fā)中,這并不是個(gè)問(wèn)題,因為通常我們都會(huì )在同一個(gè)層面上實(shí)現多個(gè)控制器,從而避免了這個(gè)缺陷;在控制器中,開(kāi)發(fā)人員可以很方便地實(shí)現一個(gè)檢查安全機制的組件,從而可以在最外層屏蔽對系統的惡意訪(fǎng)問(wèn),另外使用控制器也會(huì )提高系統模塊的可重用性,尤其在控制器同時(shí)使用幫助類(lèi)的時(shí)候。
4、視圖幫助
視圖幫助(View helper)是屬于表示層的設計模式,一個(gè)視圖幫助可以包含相關(guān)視圖中的數據訪(fǎng)問(wèn)和內容顯示的邏輯,并可以精煉簡(jiǎn)化視圖;顯示邏輯主要是關(guān)于如何格式化頁(yè)面上的數據,而訪(fǎng)問(wèn)邏輯則是關(guān)于如何取出數據,視圖幫助通常用來(lái)顯示數據的JSP標記(tag)或是讀取數據的JavaBean。
這種設計模式的出現主要是由于目前的應用系統通常需要實(shí)時(shí)地開(kāi)發(fā)顯示內容,并且能處理動(dòng)態(tài)的程序數據。如果這些程序數據的訪(fǎng)問(wèn)邏輯和顯示邏輯的關(guān)系過(guò)于緊密,則系統的表示層就會(huì )經(jīng)常需要改動(dòng),從而系統的靈活性、重用性會(huì )大大地受到破壞;同時(shí)在相同的模塊中實(shí)現訪(fǎng)問(wèn)邏輯和顯示邏輯將會(huì )影響系統的模塊化,也會(huì )使得開(kāi)發(fā)團隊的任務(wù)劃分不清。
一個(gè)視圖通常包含格式化信息,并將其處理任務(wù)分發(fā)給自己的幫助類(lèi),后者通常是用JavaBeans或標記(tag)來(lái)實(shí)現的,幫助類(lèi)同時(shí)可以存儲視圖的中間數據模型并實(shí)現數據適配器的功能,即適當地轉化數據格式;開(kāi)發(fā)人員可以采用多種方法實(shí)現視圖組件,通常,開(kāi)發(fā)人員可以使用JSP來(lái)實(shí)現,并且這也是一種值得推薦的方法。當然,相應地開(kāi)發(fā)人員也可以使用Servlet來(lái)實(shí)現它,將視圖中一定的程序邏輯植入到幫助類(lèi)中,會(huì )有利于應用系統的模塊化和可重用性。系統可以使用同一個(gè)幫助類(lèi)為不同的用戶(hù)顯示不同的數據信息,并在不同的顯示格式下顯示;通常,如果開(kāi)發(fā)人員發(fā)現視圖的JSP頁(yè)面中存在大量的腳本代碼時(shí),就可以考慮使用視圖幫助這種模式了,因為在這種情況下,基本都是程序邏輯和顯示邏輯具有過(guò)于緊密的聯(lián)系;這時(shí)開(kāi)發(fā)人員可以將一些適用于所有類(lèi)型的請求的邏輯處理放置到一定的幫助類(lèi)中,而根據需要,也可以將另外一些邏輯處理放置在視圖層上的其他程序模塊中,比如說(shuō)以前討論過(guò)的截取過(guò)濾器。
視圖幫助這種模式的設計理念主要是分離應用系統的邏輯職責,下面我們提供一些圖示,以方便大家更好地理解這種模式。
圖4以類(lèi)圖(class diagram)的形式說(shuō)明了視圖幫助的系統結構。
圖4 視圖幫助類(lèi)圖
圖5表示了視圖幫助模式的序列圖,它表明了這種模式中的主要成分及互相之間的運行情況;不過(guò)需要說(shuō)明的是,在很多應用系統中,客戶(hù)端和視圖層之間會(huì )存在一個(gè)控制器加以適當的調節。
圖5視圖幫助序列圖
在類(lèi)圖表中,大家可以發(fā)現,可能存在沒(méi)有任何相關(guān)幫助類(lèi)的視圖,這種情況下,通常代表視圖的JSP頁(yè)面會(huì )有一些靜態(tài)的或小數量的腳本代碼。
這里我們對于序列圖中的各個(gè)元素加以簡(jiǎn)單的介紹:
(1)視圖(view)。視圖負責向用戶(hù)展示動(dòng)態(tài)數據信息,而幫助類(lèi)則負責支持視圖的工作,即打包和建立相應的數據模型。
(2)幫助類(lèi)(helper)。一個(gè)幫助類(lèi)負責幫助視圖或控制器完成相關(guān)的處理工作,包括收集數據、存儲中間模型等;幫助類(lèi)也可以在保證數據完整性和準確性的情況下,為不同顯示需求修改數據模型,也就是說(shuō),根據用戶(hù)的請求,幫助類(lèi)可以向視圖提供未經(jīng)處理的原始數據,或是已經(jīng)格式化后的Web內容;一個(gè)視圖同時(shí)可以和多個(gè)幫助類(lèi)協(xié)同工作,而后者通常是由JavaBeans和標記(tag)實(shí)現的。
(3)值bean(ValueBean)。值bean實(shí)際上是用于存儲中間數據模型的幫助類(lèi)的另一種叫法,例如在序列圖5中,business service就根據請求返回了一個(gè)值bean。
(4)業(yè)務(wù)服務(wù)(business service)。業(yè)務(wù)服務(wù)是指用戶(hù)試圖得到的,應用系統可以提供的相關(guān)服務(wù);通常來(lái)說(shuō),業(yè)務(wù)服務(wù)可以通過(guò)一個(gè)業(yè)務(wù)代表(business delegate)來(lái)訪(fǎng)問(wèn),而后者主要是提供對于業(yè)務(wù)服務(wù)的控制和保護。
在應用系統的視圖模塊中使用幫助類(lèi)可以將不同的程序邏輯很好地分離開(kāi)來(lái),并在視圖模塊之外為開(kāi)發(fā)人員提供設計程序邏輯的空間;基于JavaBean和標記(tag)所開(kāi)發(fā)的幫助類(lèi)通常都可以被多個(gè)視圖模塊重用,因此也提高了組件的重用性和可維護性;把顯示邏輯從數據處理邏輯分離出來(lái),也有利于開(kāi)發(fā)團隊中角色及人物的劃分;比如說(shuō),如果各種程序邏輯過(guò)于結合的話(huà),軟件開(kāi)發(fā)人員可能需要在HTML,網(wǎng)頁(yè)中修改代碼而Web設計師則需要在處理數據訪(fǎng)問(wèn)的JSP中修改頁(yè)面布置,這些情況都可能會(huì )導致系統設計和開(kāi)發(fā)中由于不同技術(shù)人員的介入,而產(chǎn)生相關(guān)的問(wèn)題。
5、會(huì )話(huà)面
會(huì )話(huà)面(session facade)模式在合作的企業(yè)對象間調節操作,并將應用函數合成一個(gè)單一簡(jiǎn)單的界面;它減少了類(lèi)之間合作的復雜性,并使得類(lèi)的調用者在該類(lèi)變化的時(shí)候無(wú)需改動(dòng),這種模式通常以一個(gè)會(huì )話(huà)bean實(shí)現,以用來(lái)隱藏底層ejb的復雜交互。
這種設計模式出現的背景在于EJB通常既包括程序數據,又包括程序邏輯,而這些代碼都會(huì )通過(guò)一定的界面作用于客戶(hù)層,在多層次的J2EE平臺應用程序中,就會(huì )造成一定的困難。
具體來(lái)說(shuō),在J2EE平臺上的多層次系統中,通常會(huì )存在以下的問(wèn)題:
(1)層次之間聯(lián)系過(guò)于緊密,客戶(hù)層和后端的業(yè)務(wù)對象具有較強的依賴(lài)關(guān)系;
(2)在客戶(hù)和服務(wù)器之間有多次方法調用,因而導致了Web性能方面的問(wèn)題;
(3)缺乏一定的客戶(hù)訪(fǎng)問(wèn)機制,使得一些后臺對象被隨便訪(fǎng)問(wèn)。
一個(gè)多層次的J2EE應用程序通常具有很多由EJB實(shí)現的服務(wù)器端對象,它們通常負責提供系統服務(wù)、數據信息等,也就是說(shuō)作為業(yè)務(wù)對象,它們既包括相關(guān)的程序數據,也包括其程序邏輯;在J2EE應用系統中,負責程序邏輯的對象通常由會(huì )話(huà)bean實(shí)現,而表示持久性存儲,并在多個(gè)用戶(hù)間共享的對象則由實(shí)體bean來(lái)實(shí)現;當然,應用系統的用戶(hù)需要訪(fǎng)問(wèn)企業(yè)對象來(lái)滿(mǎn)足自己的需求,如果企業(yè)對象向用戶(hù)提供接口,用戶(hù)可以直接地與相關(guān)對象通信,但是這樣一來(lái),用戶(hù)必須負責管理所調用的企業(yè)對象之間的關(guān)系,并且能夠處理其間的業(yè)務(wù)流程;然而,如果用戶(hù)和業(yè)務(wù)對象之間存在過(guò)于直接的交互,兩者的聯(lián)系就會(huì )過(guò)于緊密,同時(shí)也使得用戶(hù)過(guò)于依賴(lài)企業(yè)對象的具體實(shí)現,并負責管理與交互過(guò)程有關(guān)的業(yè)務(wù)對象查找和創(chuàng )建,以及不同的對象間相互調用的關(guān)系,甚至一些時(shí)候用戶(hù)還需要管理多次調用之間的事務(wù)管理環(huán)節。
在用戶(hù)需求不斷增加時(shí),這也是應用系統經(jīng)常發(fā)生的情況,用戶(hù)與不同的企業(yè)對象之間的交互也會(huì )變得越來(lái)越復雜,而企業(yè)對象可能需要一定內部的更新才能滿(mǎn)足前者的需要,但是這樣的話(huà)用戶(hù)又需要根據企業(yè)對象實(shí)現的變化而做出相應的改變,這種情況將為應用系統帶來(lái)相當大的麻煩;在訪(fǎng)問(wèn)EJB應用系統時(shí),用戶(hù)需要與遠程對象進(jìn)行交互。如果用戶(hù)直接與所有相關(guān)的業(yè)務(wù)對象交互的話(huà),將帶來(lái)很大的Web負擔;因為對于每一個(gè)ejb的激活,都將產(chǎn)生一次遠程的調用,而如果存在大量的系統用戶(hù),用戶(hù)與對象間的交互就將為Web通信帶來(lái)很大的壓力,使系統性能受到很大破壞;如果用戶(hù)可以直接訪(fǎng)問(wèn)后端的企業(yè)對象,但是系統中又缺少一個(gè)統一的用戶(hù)訪(fǎng)問(wèn)機制,那么這些訪(fǎng)問(wèn)很有可能變得雜亂無(wú)章,引起系統性能的下降,甚至導致一些安全問(wèn)題。
為了解決以上的問(wèn)題,開(kāi)發(fā)人員可以采用會(huì )話(huà)面的設計模式,即使用會(huì )話(huà)bean來(lái)實(shí)現一個(gè)面(facade)來(lái)包含一個(gè)工作流中所有相關(guān)對象的交互;這個(gè)會(huì )話(huà)面負責管理業(yè)務(wù)對象,并向用戶(hù)提供一個(gè)統一的服務(wù)訪(fǎng)問(wèn)層,會(huì )話(huà)面可以面向底層對象的交互過(guò)程,并提供一個(gè)僅僅包含必須提供的接口的服務(wù)層,由此它將復雜的對象交互和用戶(hù)之間隔離開(kāi)來(lái); 會(huì )話(huà)面也負責管理企業(yè)數據和企業(yè)對象之間的交互,并表達其中需要的企業(yè)邏輯,因此會(huì )話(huà)面也可以管理企業(yè)對象之間的作用關(guān)系;同時(shí),根據工作流的需要,會(huì )話(huà)面也管理對象的創(chuàng )建、查找、修改和刪除。
在一個(gè)復雜的應用系統中,會(huì )話(huà)面可以將其生命周期的管理下放到一個(gè)單獨的幫助對象去,比如說(shuō),會(huì )話(huà)面可以將管理會(huì )話(huà)和實(shí)體bean生命周期的工作交給服務(wù)定位對象; 同時(shí),在應用系統中,檢查業(yè)務(wù)對象之間的作用關(guān)系也是非常重要的,一些關(guān)系可能是暫時(shí)的,即只使用于一定的交互過(guò)程,而另外一些關(guān)系則是永久的,暫時(shí)的關(guān)系適合建模于會(huì )話(huà)面中的工作流,永久的關(guān)系則需要具體情況具體分析。
圖6中的類(lèi)圖簡(jiǎn)要描述了會(huì )話(huà)面的設計模式,圖7給出了會(huì )話(huà)面的序列表示,即參與組件及其交互關(guān)系。
圖6 會(huì )話(huà)面類(lèi)圖
圖7會(huì )話(huà)面序列圖
這里我們對于圖7的各個(gè)組件加以簡(jiǎn)要的介紹:
(1)客戶(hù)(Client)。這表示會(huì )話(huà)面的客戶(hù),即需要訪(fǎng)問(wèn)相關(guān)企業(yè)服務(wù)的客戶(hù)端應用程序,當然也可以是在同一層面或不同層面的另外一個(gè)會(huì )話(huà)bean。
(2)會(huì )話(huà)面(Session Facade)。會(huì )話(huà)面通常是用會(huì )話(huà)bean來(lái)實(shí)現的,它管理著(zhù)多個(gè)企業(yè)對象的作用關(guān)系并提供一個(gè)高層次的抽象界面給用戶(hù)。
(3)業(yè)務(wù)對象(Business Object)。業(yè)務(wù)對象是一個(gè)可以使用多個(gè)不同設計方案的對象,例如會(huì )話(huà)bean、實(shí)體bean和數據訪(fǎng)問(wèn)對象。在圖6中業(yè)務(wù)對象負責提供數據和服務(wù),而會(huì )話(huà)面則需要與多個(gè)業(yè)務(wù)對象實(shí)例交互而獲得相應的服務(wù)。
會(huì )話(huà)面實(shí)際上就是業(yè)務(wù)層的一個(gè)控制對象,它負責控制用戶(hù)與企業(yè)數據和企業(yè)服務(wù)對象之間的交互;在一個(gè)復雜的應用系統中,甚至可能會(huì )有多個(gè)會(huì )話(huà)面作為用戶(hù)和對象模塊之間的中介。
下面介紹兩種實(shí)現會(huì )話(huà)面的常見(jiàn)方法。
(1)無(wú)狀態(tài)的會(huì )話(huà)面
在實(shí)現會(huì )話(huà)面的時(shí)候,首先應該決定是用狀態(tài)化還是無(wú)狀態(tài)的會(huì )話(huà)bean來(lái)實(shí)現,這主要取決于會(huì )話(huà)面所建模的業(yè)務(wù)流程;如果一個(gè)業(yè)務(wù)流程只需要一次方法調用就可以實(shí)現其服務(wù),那么就可以使用無(wú)狀態(tài)的會(huì )話(huà)bean來(lái)實(shí)現它。
(2)狀態(tài)化的會(huì )話(huà)面
當一個(gè)業(yè)務(wù)流程需要多次方法調用來(lái)實(shí)現其服務(wù)時(shí),開(kāi)發(fā)人員最好使用狀態(tài)化的會(huì )話(huà)bean來(lái)實(shí)現這一流程,因為每次方法調用的狀態(tài)信息都必須在會(huì )話(huà)bean中保存。
通過(guò)在應用系統中采用會(huì )話(huà)面的設計模式,將在系統中得到以下的收益:
①為用戶(hù)提供一個(gè)簡(jiǎn)單的接口,并隱藏所有與系統組件復雜的交互過(guò)程;
②減少暴露給用戶(hù)的企業(yè)對象,從而降低它們之間的依賴(lài)關(guān)系;
③向用戶(hù)隱藏系統組件間的交互過(guò)程和依賴(lài)關(guān)系,從而使得系統更加容易管理,并提供相當的靈活性;提供一套統一的用戶(hù)訪(fǎng)問(wèn)機制,便于管理用戶(hù)對于系統服務(wù)的請求與訪(fǎng)問(wèn)。
6、 數據訪(fǎng)問(wèn)對象
數據訪(fǎng)問(wèn)對象(data access object,DAO)模式將數據訪(fǎng)問(wèn)邏輯抽象為特殊的資源,也就是說(shuō)將系統資源的接口從其底層訪(fǎng)問(wèn)機制中隔離出來(lái);通過(guò)將數據訪(fǎng)問(wèn)的調用打包,數據訪(fǎng)問(wèn)對象可以促進(jìn)對于不同數據庫類(lèi)型和模式的數據訪(fǎng)問(wèn)。
這種模式出現的背景在于數據訪(fǎng)問(wèn)的邏輯極大程度上取決于數據存儲的格式,比如說(shuō)關(guān)系型數據庫、面向對象數據庫、磁盤(pán)文件等。
目前大部分的J2EE應用程序都需要在一定程度上使用可持久性的數據,而實(shí)現持久性數據的方法因應用程序不同而異,并且訪(fǎng)問(wèn)不同存儲格式數據的應用程序接口(API)也有著(zhù)顯著(zhù)的差別;有的時(shí)候,應用程序還會(huì )訪(fǎng)問(wèn)存儲在不同操作平臺上的數據,這使得問(wèn)題更為復雜,通常,應用程序會(huì )使用共享的分布式組件,如實(shí)體bean來(lái)表達持久性數據。應用程序可以使用bean管理的持久性實(shí)體bean,而在實(shí)體bean中植人數據訪(fǎng)問(wèn)邏輯,或者使用容器管理的持久性實(shí)體bean,從而使容器管理所有的事務(wù)和持久性細節;而如果應用程序對于數據訪(fǎng)問(wèn)的需求十分簡(jiǎn)單的話(huà),也可以采用會(huì )話(huà)bean或Servlet直接訪(fǎng)問(wèn)持久性存儲來(lái)讀取和修改數據。
一些應用程序可以使用JDBC應用程序接口來(lái)訪(fǎng)問(wèn)關(guān)系數據庫中的數據,JDBC負責一般的持久性數據訪(fǎng)問(wèn)和管理,在J2EE應用程序中,JDBC中可以嵌入SQL語(yǔ)句,用以訪(fǎng)問(wèn)關(guān)系型數據庫,當然根據數據庫類(lèi)型的不同,SQL語(yǔ)句的詞法和語(yǔ)法也會(huì )有所不同;需要說(shuō)明的是,當數據存儲格式不同的時(shí)候,數據訪(fǎng)問(wèn)邏輯的區別就更加明顯了,例如關(guān)系型數據庫、面向對象數據庫和磁盤(pán)文件,各自數據的訪(fǎng)問(wèn)邏輯各有千秋,這樣一來(lái)就造成了程序代碼和數據訪(fǎng)問(wèn)代碼之間的依賴(lài)關(guān)系;當程序組件,即實(shí)體bean、會(huì )話(huà)bean或servlet、JSP等需要訪(fǎng)問(wèn)數據源時(shí),它們會(huì )使用正確的應用程序接口來(lái)得到連接并管理數據源,但這樣也會(huì )造成這些組件與數據源物理實(shí)現之間的依賴(lài)關(guān)系,從而使得應用程序很難從一個(gè)數據存儲實(shí)體移植到另一個(gè)數據存儲實(shí)體中去;當數據源的物理實(shí)現變化的時(shí)候,應用程序也必須相應地加以改變。
基于以上所討論的問(wèn)題,開(kāi)發(fā)人員開(kāi)始采用數據訪(fǎng)問(wèn)對象的方法。數據訪(fǎng)問(wèn)對象實(shí)際上就是包含對于所有數據訪(fǎng)問(wèn)邏輯的對象,并管理著(zhù)對于數據源的連接,根據數據源的不同,數據訪(fǎng)問(wèn)對象實(shí)現了不同的訪(fǎng)問(wèn)機制,這里所說(shuō)的數據源可以是持久性存儲介質(zhì),如關(guān)系型數據庫,也可以是外部服務(wù),如B2B的數據交換;不僅是用戶(hù),而且包括應用系統中的其他組件,也可以使用數據訪(fǎng)問(wèn)對象所提供的數據訪(fǎng)問(wèn)接口,數據訪(fǎng)問(wèn)對象將數據源的物理實(shí)現細節與其用戶(hù)完全分離開(kāi)來(lái),并且在底層數據源變化的時(shí)候,數據訪(fǎng)問(wèn)對象向用戶(hù)提供的接口是不會(huì )變化的;這種方法使應用系統使用數據訪(fǎng)問(wèn)對象時(shí)可以適應多種數據存儲介質(zhì),總之,數據訪(fǎng)問(wèn)對象就是系統組件和數據源中間的適配器。
圖8中的類(lèi)圖表示了數據訪(fǎng)問(wèn)對象設計模式的參與對象和之間的調用關(guān)系,圖9是這種設計模式的序列圖。
圖8 數據訪(fǎng)問(wèn)對象類(lèi)圖
圖9 數據訪(fǎng)問(wèn)對象序列圖
對于圖9序列圖中的組件加以解釋如下:
(1)業(yè)務(wù)對象(Business Object)。表示數據的用戶(hù),它需要對于數據的訪(fǎng)問(wèn),一個(gè)業(yè)務(wù)對象可以用會(huì )話(huà)bean、實(shí)體bean或是其他Java程序來(lái)實(shí)現。
(2)數據訪(fǎng)問(wèn)對象(Data Access Object)。數據訪(fǎng)問(wèn)對象是這種模式中的主題,它提供了底層數據訪(fǎng)問(wèn)的對象,并將其提供給業(yè)務(wù)對象以使得后者能夠透明地訪(fǎng)問(wèn)數據源;同時(shí)業(yè)務(wù)對象也將數據的加載和存儲操作移交給數據訪(fǎng)問(wèn)對象處理。
(3)數據源(Data source)。這里指的是數據源的物理實(shí)現,這個(gè)數據源可以是一個(gè)數據庫,包括關(guān)系型數據庫、面向對象數據庫或文件系統。
(4)傳輸對象(Transfer Object)。這里的傳輸對象指的是數據載體。數據訪(fǎng)問(wèn)對象可以使用傳輸對象來(lái)向用戶(hù)返回數據,而數據訪(fǎng)問(wèn)對象同樣可以從用戶(hù)那里得到傳輸對象來(lái)對數據源中的數據進(jìn)行更新。
下面給出幾種實(shí)現數據訪(fǎng)問(wèn)對象設計模式的方法。
(1)自動(dòng)數據訪(fǎng)問(wèn)對象代碼的生成
既然每一個(gè)業(yè)務(wù)對象都對應于一個(gè)數據訪(fǎng)問(wèn)對象,那么開(kāi)發(fā)人員就可以建立業(yè)務(wù)對象、數據訪(fǎng)問(wèn)對象和底層實(shí)現的關(guān)系;一旦這種關(guān)系建立起來(lái),開(kāi)發(fā)人員就可以為所有的數據訪(fǎng)問(wèn)對象編寫(xiě)特殊的代碼生成工具。
生成數據訪(fǎng)問(wèn)對象的信息通常存儲在一個(gè)開(kāi)發(fā)人員定義的描述文件中,如果對于數據訪(fǎng)問(wèn)對象的要求過(guò)于復雜,開(kāi)發(fā)人員可以考慮使用第三方工具來(lái)為關(guān)系型數據庫提供對象對關(guān)系的映射。這些工具通常是一些GUI程序,可以用來(lái)將業(yè)務(wù)對象映射為持久性的存儲對象,并定義中間運作的數據訪(fǎng)問(wèn)對象,在映射完成的時(shí)候,這些工具可以自動(dòng)地生成代碼,并提供一些相應的功能,如緩存結果、緩存查詢(xún)、與應用服務(wù)器整合、與第三方產(chǎn)品整合等。
(2)數據訪(fǎng)問(wèn)對象代理(Factory for Data Access Objects)
當底層的數據存儲不會(huì )輕易改變的時(shí)候,開(kāi)發(fā)人員可以采取這種方法來(lái)實(shí)現相應的,數據訪(fǎng)問(wèn)對象,圖10是這種方法的類(lèi)圖。
圖10 使用DAO代理類(lèi)圖
當底層的數據存儲可能會(huì )變化的時(shí)候,開(kāi)發(fā)人員可以采用抽象代理的方法來(lái)實(shí)現數據訪(fǎng)問(wèn)對象;抽象代理的方法會(huì )創(chuàng )建一些虛擬的數據訪(fǎng)問(wèn)對象代理和各種類(lèi)型的實(shí)際數據訪(fǎng)問(wèn)對象代理,每種對象對應一種持久性存儲介質(zhì)的實(shí)現,一旦組件得到這些代理,就可以利用來(lái)創(chuàng )建需要使用的數據訪(fǎng)問(wèn)對象。
圖11給出了這種情況的類(lèi)圖。該類(lèi)圖表示了一個(gè)基礎的數據訪(fǎng)問(wèn)對象代理,它是一個(gè)抽象類(lèi),被其他一些實(shí)際的數據訪(fǎng)問(wèn)對象代理繼承以支持特定的數據訪(fǎng)問(wèn)函數;用戶(hù)可以得到一個(gè)實(shí)際的數據訪(fǎng)問(wèn)對象,并利用它來(lái)創(chuàng )建需要的數據訪(fǎng)問(wèn)對象而訪(fǎng)問(wèn)相關(guān)的數據,每一個(gè)實(shí)際的數據訪(fǎng)問(wèn)對象都負責建立對于數據源的連接,并得到和管理所支持的業(yè)務(wù)數據。
圖11 抽象代理使用DAO
下圖12是這種情況下的序列圖。
圖12抽象代理使用DAO序列圖
這種設計模式的優(yōu)勢:
這種設計模式的缺陷:
總之,在開(kāi)發(fā)人員選擇不同模式的時(shí)候,應該注意,一定的模式對應于一定的應用層次。比如說(shuō),與視圖和顯示相關(guān)的模式就是在Web層應用的。而一些與業(yè)務(wù)邏輯控制相關(guān)的模式則是與EJB層次相關(guān)的。另外一些關(guān)于讀取數據和分派操作的模式則適用于不同的層次之間。
7、值對象或傳輸對象
值對象(value object)模式通過(guò)減少分布式通信的消息而促進(jìn)數據的交換,通常這里所指的通信是在Web層和EJB層之間。在一個(gè)遠程調用中,一個(gè)單一值對象可以被用來(lái)取出一系列相關(guān)數據并提供給客戶(hù)。
這種設計模式的出現是基于客戶(hù)需要與ejb大量地交換數據的情況。具體來(lái)說(shuō),在J2EE平臺中,應用系統通常將服務(wù)器端的程序組件實(shí)現為會(huì )話(huà)bean和實(shí)體bean,而這些組件的部分方法則需要將數據返回給客戶(hù);這種情況下,通常一個(gè)用戶(hù)會(huì )重復調用相關(guān)方法多次,直到它得到相關(guān)信息,應該注意的是,多數情況這些方法調用的目的都是為了取得單一的信息,例如用戶(hù)名或者用戶(hù)地址等。
顯而易見(jiàn),在J2EE平臺上,這種調用基本上都是來(lái)自遠程的。也就是說(shuō),用戶(hù)多次調用相應的方法會(huì )給Web帶來(lái)極大的負擔,即使用戶(hù)和EJB容器加載相同的JVM、OS和計算機上運行EJB程序,由于方法調用被缺省地認為是遠程任務(wù),所以這種問(wèn)題依然存在。
由于以上所提到的問(wèn)題,在遠程方法的調用次數增加的時(shí)候,相關(guān)的應用程序性能將會(huì )有很大的下降,因此利用多次方法調用而取得單一的信息是非常低效的;在這種情況,J2EE的研究人員建議使用傳輸對象來(lái)包含所有的程序數據,即每次方法調用可以發(fā)送和接收這個(gè)傳輸對象;當用戶(hù)向EJB發(fā)出對于程序數據的請求時(shí),EJB會(huì )創(chuàng )建這個(gè)傳輸對象,將它的各個(gè)域賦以相關(guān)的數值,并將整個(gè)對象傳送給用戶(hù)。
當EJB使用傳輸對象的時(shí)候,用戶(hù)可以通過(guò)僅僅一次方法調用來(lái)取得整個(gè)對象,而不是使用多次方法調用以得到對象中每個(gè)域的數值;由于傳輸對象是通過(guò)值傳遞而交送給用戶(hù)的,所以所有對于該傳輸對象的調用或取值都是本地調用,而不是遠程方法調用。不過(guò)需要注意的是,這個(gè)傳輸對象必須具有對應于每個(gè)屬性的訪(fǎng)問(wèn)方法,或者將所有屬性都設為公共的。
類(lèi)圖13表示了傳輸對象模式的體系結構。
圖13 傳輸對象類(lèi)圖
在圖13中,傳輸對象首先在EJB中創(chuàng )建,然后返回給遠程客戶(hù);當然,傳輸對象也可以根據需要融合其他的設計模式。
圖14顯示了傳輸對象模式中的參與模塊和它們之間的交互。
圖14 傳輸對象序列圖
下面我們說(shuō)明一下傳輸對象模式的各個(gè)參與模塊:
(1)客戶(hù)(Client)??蛻?hù)代表了EJB所提供服務(wù)的使用者,通常是運行于用戶(hù)終端的應用程序。
(2)業(yè)務(wù)對象。業(yè)務(wù)對象表示在一個(gè)模式中由會(huì )話(huà)bean、實(shí)體bean或數據訪(fǎng)問(wèn)對象(Data Access Object)實(shí)現的角色。業(yè)務(wù)對象通常負責創(chuàng )建傳輸對象,并根據請求將其傳送到相關(guān)的用戶(hù);業(yè)務(wù)對象也可以從用戶(hù)中取得一個(gè)傳輸對象格式的數據,并應用這些數據來(lái)執行一些更新。
(3)傳輸對象。傳輸對象是一個(gè)可序列化的Java對象。在這個(gè)對象的類(lèi)中,通常會(huì )有一個(gè)包含所有域的構造函數,用來(lái)創(chuàng )建這個(gè)傳輸對象。
這個(gè)傳輸對象中的成員變量基本都被定義為公共,從而無(wú)需為它們提供相關(guān)的訪(fǎng)問(wèn)方法。當然如果存在一定安全的需要,相關(guān)的成員變量也可以設為保護或私有,并且給定各自的訪(fǎng)問(wèn)方法。由此可見(jiàn),傳輸對象的設計是隨著(zhù)應用系統的需要不同而改變的,是否將對象中的成員變量設為公共,或提供一定的訪(fǎng)問(wèn)方法,將是一個(gè)很重要的設計問(wèn)題。
通常在實(shí)現這個(gè)模式時(shí),最多采取的是可更新的傳輸對象策略和多傳輸對象策略。 在可更新的傳輸對象策略中,傳輸對象不僅可以從服務(wù)于用戶(hù)的業(yè)務(wù)對象中取得相關(guān)信息和數據,還可以從業(yè)務(wù)對象中得到用戶(hù)對于數據所需要進(jìn)行的改變。
圖15以類(lèi)圖表的形式表明了業(yè)務(wù)對象和傳輸對象之間的關(guān)系。
圖15 可更新傳輸對象類(lèi)圖
業(yè)務(wù)對象創(chuàng )建了傳輸對象。而用戶(hù)通過(guò)訪(fǎng)問(wèn)業(yè)務(wù)對象,既得到了所需的信息,也對相關(guān)數據做出了一定的修改;為了能夠使得用戶(hù)可以修改業(yè)務(wù)對象各個(gè)域的取值,這個(gè)對象必須提供一定的變值方法,而出于對Web負擔的考慮,業(yè)務(wù)對象所提供的方法最好以傳輸對象為參數。相應地,這些方法可以去調用傳輸對象所提供的方法,來(lái)設置傳輸對象的各個(gè)成員變量的取值;同時(shí)在傳輸對象的方法中,我們也可以植入數據驗證和完整性檢查的邏輯,這樣在用戶(hù)從業(yè)務(wù)對象的方法得到傳輸對象時(shí),可以直接調用傳輸對象的成員方法進(jìn)行本地數據訪(fǎng)問(wèn),當然這種本地數據訪(fǎng)問(wèn)不會(huì )影響到業(yè)務(wù)對象。
當用戶(hù)調用業(yè)務(wù)對象的變值方法時(shí),該方法會(huì )將用戶(hù)端的傳輸對象序列化,再將它發(fā)送給業(yè)務(wù)對象;業(yè)務(wù)對象接收到更新的傳輸對象,便將這些更新寫(xiě)回到自己的對象拷貝中去; 這里需要說(shuō)明的是,上面提到的寫(xiě)回只是涉及到被更新的變量,而不是全部變量的寫(xiě)回,因此我們需要在傳輸對象中另設置一個(gè)變量,來(lái)指定哪些成員變量被用戶(hù)更新過(guò),這也就使得這種模式的設計相對復雜,開(kāi)發(fā)人員需要考慮同步化和版本控制的問(wèn)題。
圖16顯示了這個(gè)更新過(guò)程的序列圖。
圖16 可更新傳輸對象序列圖
多傳輸對象的方法是指一個(gè)單一的業(yè)務(wù)對象可以根據用戶(hù)請求制造多個(gè)不同的傳輸對象。也就是說(shuō),業(yè)務(wù)對象和它所創(chuàng )建的傳輸對象保持一對多的關(guān)系。類(lèi)圖17表示了這種實(shí)現方法的各個(gè)參與模塊以及它們之間的調用關(guān)系。
圖17 多傳輸對象類(lèi)圖
當一個(gè)用戶(hù)需要A類(lèi)型的傳輸對象時(shí),他會(huì )激活相關(guān)EJB的getDataA()方法來(lái)取得傳輸對象A;當他需要B類(lèi)型的傳輸對象時(shí),他會(huì )激活getDataB()方法來(lái)獲取傳輸對象B;依此類(lèi)推。序列圖18表示了這一過(guò)程。
圖18 多傳輸對象序列圖
使用這種設計模式,應用系統的實(shí)體bean及其遠程接口會(huì )變得十分簡(jiǎn)單。實(shí)體bean中無(wú)需再為每一個(gè)成員變量都實(shí)現一個(gè)set()和get()方法,并在遠程接口中實(shí)現相應的定義。用戶(hù)無(wú)需再進(jìn)行多次的方法調用來(lái)取得信息和數據,所需要的只是一次方法調用以獲得整個(gè)傳輸對象。當然這里需要考慮Web負擔和大量數據一次傳輸的權衡。開(kāi)發(fā)人員可以根據不同的需要來(lái)選擇不同的實(shí)現方法。
如上所述,用戶(hù)和實(shí)體bean之間可以通過(guò)在一次方法調用中使用傳輸對象而交換所有的數據,也就是說(shuō)傳輸對象作為數據載體工作,并減少了遠程的方法調用,從而大大減輕了Web負擔。通過(guò)使用傳輸對象的方法,我們也將有可能減少實(shí)體bean和其傳輸對象間的代碼重復。不過(guò)在使用可更新的傳輸對象方法時(shí),用戶(hù)可以修改其本地的傳輸對象,之后再將其傳送回業(yè)務(wù)對象中,后者將所需的更新整合到自己一端;但是這樣一來(lái),就會(huì )存在一個(gè)版本控制的問(wèn)題,不同的客戶(hù)可能在同時(shí)修改相同類(lèi)型的傳輸對象,而如果相關(guān)的業(yè)務(wù)對象沒(méi)有發(fā)現這一點(diǎn)的話(huà),可能就會(huì )造成一些用戶(hù)的數據沒(méi)有得到及時(shí)更新,而另外一些用戶(hù)的數據又被覆蓋的情況;在系統設計中必須考慮這個(gè)問(wèn)題。
8、截取過(guò)濾器
截取過(guò)濾器(intercepting filter)主要用于對于用戶(hù)請求的之前處理和之后處理,也就是說(shuō)它對于客戶(hù)的請求使用了額外的操作。比如說(shuō),servlet可以處理一個(gè)網(wǎng)站的所有客戶(hù)請求并提供一個(gè)核心的認證機制。
這種模式主要工作于表示層,負責處理不同類(lèi)型的請求,同時(shí)也需要進(jìn)行多種不同的處理。在這些請求中,有一些請求會(huì )直接傳送給后端模塊處理,而另外一些請求則先會(huì )在過(guò)濾器里解釋或補充內容,之后才能傳送給后端模塊。這種模式的提出主要是由于一個(gè)客戶(hù)的Web訪(fǎng)問(wèn)和系統響應都需要一定的預處理和后處理,例如用戶(hù)身份、用戶(hù)環(huán)境信息、用戶(hù)請求的合法性等。通常這些處理的結果都會(huì )決定用戶(hù)的請求是否能夠進(jìn)行,或是系統的響應應該用什么格式來(lái)表示。
對于這種預處理和后處理問(wèn)題,傳統上,開(kāi)發(fā)人員會(huì )設計一系列額外的檢測程序模塊,也就是一整套if/else語(yǔ)句,并且指定如果其中任何一個(gè)檢測失敗,所有的處理工作都會(huì )退出。顯然,這種方法是存在很大弊端的,即代碼的可讀性、可維護性都會(huì )被大大降低,同時(shí)將檢測工作融于一般的程序模塊,使得整個(gè)程序的模塊性難以保證。
解決這種問(wèn)題的關(guān)鍵在于,設計一種簡(jiǎn)單的技術(shù),以能夠添加或移除額外處理的模塊,而這些模塊通常都能夠完成一定的檢測和過(guò)濾功能。根據以上的討論,J2EE研究人員提出了設計模式----截取過(guò)濾器作為解決方案,這種模式可以在不影響核心處理模塊的情況下,實(shí)現可插入的過(guò)濾器來(lái)執行一般的處理功能。
從理論上來(lái)說(shuō),這種過(guò)濾器可以截取客戶(hù)請求和系統響應,并進(jìn)行相應的預處理和后處理;同時(shí)開(kāi)發(fā)人員也可以隨時(shí)根據需要移除這些過(guò)濾器,并不用擔心會(huì )改變任何其他模塊。
我們這里所說(shuō)的預處理和后處理功能,通常是指一些基本的系統服務(wù),如安全、登錄,系統調試等。執行這些功能的過(guò)濾器通常是需要與核心模塊分開(kāi)的,并且由于系統職能或規則的變化,這些模塊隨時(shí)可能被添加或刪除。
下面提供一些關(guān)于截取過(guò)濾器的圖示,以幫助大家更好地理解這種設計模式,并合理地加以運用。圖19表示了截取過(guò)濾器模式的整體結構,圖19顯示了截取過(guò)濾器中的參與模塊和相互之間的聯(lián)系。
圖19 截取過(guò)濾器模式
圖20 截取過(guò)濾器序列圖
下面我們分別來(lái)說(shuō)明圖20中的各個(gè)模塊:
(1)過(guò)濾管理器(Filter Manager)。過(guò)濾管理器負責過(guò)濾器的主要處理工作,即創(chuàng )建過(guò)濾器鏈對象以及相應的過(guò)濾器組建,并初始化整個(gè)處理過(guò)程。
(2)過(guò)濾器鏈(Filter Chain)。過(guò)濾器鏈是一組互不依賴(lài)的過(guò)濾器有序集合。
(3)過(guò)濾器1,過(guò)濾器2,過(guò)濾器3(FilterOne,FilterTwo,FilterThree)。這些都是提供不同服務(wù)的過(guò)濾器,而過(guò)濾器鏈則負責它們的協(xié)調工作。
通過(guò)采用這種設計模式,應用系統可以取得更方便的中心控制,這是由于過(guò)濾器可以提供處理多種請求的中心模塊,并能根據后端的處理模塊而解釋和潤色用戶(hù)的請求,使得該請求能更好地與處理模塊所提供的功能匹配。另外,過(guò)濾器通??梢詫⒉煌N類(lèi)的服務(wù)聚集在一起,并提供相當靈活的服務(wù)組合,應用系統可以通過(guò)使用截取過(guò)濾器提高其重用性,過(guò)濾器可以隨時(shí)根據需要從其他程序模塊中插入或移除,并且由于它們通常具有標準的接口,開(kāi)發(fā)人員可以使用一組類(lèi)似的過(guò)濾器,并在不同的情況下進(jìn)行全組的重用。
采用這種設計模式也會(huì )帶來(lái)一定的問(wèn)題,即在過(guò)濾器之間共享信息將變得非常困難,這是由于根據其定義和需求,每個(gè)過(guò)濾器的設計和開(kāi)發(fā)都大相徑庭。因而如果在不同的過(guò)濾器之間需要共享信息的話(huà),其代價(jià)將是非常昂貴的。
作者:務(wù)實(shí),多年從事J2EE網(wǎng)站及應用系統項目的開(kāi)發(fā)和應用。
聯(lián)系客服