EJB 倡導(dǎo)者對(duì)面向服務(wù)的體系結(jié)構(gòu)從上至下進(jìn)行了分析,以最終確定應(yīng)該使用會(huì)話 EJB 組件還是實(shí)體 EJB 組件組裝服務(wù)返回的數(shù)據(jù)傳輸對(duì)象。<!--START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --> <!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
在每個(gè)專欄中,EJB 倡導(dǎo)者提出要點(diǎn),客戶和開發(fā)者采用獨(dú)特的前后銜接的對(duì)話框方式,在對(duì)某一感興趣的設(shè)計(jì)問題提議解決方案的過程中進(jìn)行交流。其中忽略了任何確定性的細(xì)節(jié),并且不提供“革新的”或?qū)S械捏w系結(jié)構(gòu)。有關(guān)詳細(xì)信息,請(qǐng)參閱 EJB 倡導(dǎo)者簡(jiǎn)介 。
在 前一篇專欄文章 中, 我們介紹了面向服務(wù)的體系結(jié)構(gòu)的一些特征;例如,為了盡可能減少服務(wù)和其客戶機(jī)間頻繁的對(duì)話,服務(wù)必須為粗粒度的無狀態(tài)服務(wù),而且必須正常組裝數(shù)據(jù)傳輸對(duì) 象 (DTO),此類對(duì)象會(huì)收集所有從客戶機(jī)應(yīng)用程序返回的屬性。我們了解了設(shè)計(jì)良好的 EJB 方法如何展示這些特征(通過與會(huì)話 EJB 實(shí)例或?qū)嶓w EJB Home 接口關(guān)聯(lián))。不過,在本月,有位讀者詢問我們是否認(rèn)為實(shí)體 EJB 組件也設(shè)計(jì)為無狀態(tài)服務(wù)。
問題:哪個(gè)數(shù)據(jù)傳輸對(duì)象由哪個(gè)實(shí)體返回?
親愛的 EJB 倡導(dǎo)者:
我已經(jīng)讀過您最近的文章,對(duì)于數(shù)據(jù)傳輸對(duì)象 (DTO),我想提出一些自己的看法。我同意您所說的,數(shù)據(jù)傳輸對(duì)象在服務(wù)層(該層中需要各種粗粒度方法)非常重要,特別對(duì)于表示隱藏實(shí)現(xiàn)的服務(wù)的外觀,尤其是遠(yuǎn)程外觀(因?yàn)檫h(yuǎn)程調(diào)用的開銷要比本地調(diào)用大得多)更是如此。
此 外,推薦的代碼看起來非常合理,并得到了良好封裝,能夠讓您要求實(shí)體 EJB 組件“給我一個(gè)您自己的 DTO”。不過有一個(gè)問題,對(duì)于兩種不同的用例,一種可能需要給定實(shí)體 EJB 組件的某些屬性,而另一種則可能需要不同的屬性,因此會(huì)需要兩個(gè) DTO 類。那么,getDTO() 方法應(yīng)該返回哪個(gè) DTO 類型呢?
還有另一個(gè)問題。不同的用例可能需要由 相同類型或不同類型(客戶、延期交貨訂單、訂單中的產(chǎn)品)的多個(gè)實(shí)例組成的 DTO。這種情況下,需要在哪個(gè)實(shí)體 EJB 中實(shí)現(xiàn)該復(fù)合功能?
在 會(huì)話外觀中,似乎不能避免對(duì)實(shí)體 EJB 組件使用單個(gè) getter(和 setter)。將組裝 DTO 的邏輯放入到會(huì)話 Bean 中(或者,按照我喜歡的方式,放入會(huì)話使用的 Helper 類中)的好處之一就是,當(dāng)由于某種原因(如添加另一個(gè)服務(wù)所需的新屬性)需要?jiǎng)h除或重新生成實(shí)體時(shí),不用擔(dān)心自定義代碼發(fā)生不同步的現(xiàn)象。
我想,我真正想問的是:您在建議使用實(shí)體 EJB 組件的本地接口時(shí),從實(shí)體 CMP 返回 DTO 是否是在“喊狼來了”?我理解您關(guān)于盡力減少各層之間的頻繁對(duì)話的觀點(diǎn),但似乎您在以犧牲可維護(hù)性為代價(jià)來換取性能的提高。
請(qǐng)用這個(gè)名字稱呼我們,
Never Cry Wolf
親愛的 Never:
您提出了很好的觀點(diǎn),非常值得加以說明。讓我們從上到下依次回答您提出的問題:
-
假設(shè)兩種用例需要不同的數(shù)據(jù),getDTO() 方法應(yīng)該返回哪個(gè) DTO 類型?
我的回答是:getDTO() 當(dāng)然應(yīng)該返回 DTO 的實(shí)例。認(rèn)真一點(diǎn)講,您為 DTO 選擇的名稱應(yīng)該清楚地指示它所返回的數(shù)據(jù)。如果兩種用例需要不同的數(shù)據(jù)集,DTO 類名稱應(yīng)該指示這一點(diǎn):可以為 UseCase1DTO 或 UseCase2DTO 之類的。因此接口中的兩個(gè)方法簽名將為:
代碼段 1. DTO 方法的多個(gè)簽名
public UseCase1DTO getUseCase1DTO();
public UseCase2DTO getUseCase2DTO();
或者,更抽象一些:
代碼段 2. 顯示抽象示例的更不易混淆的方式
public <DTO> get<DTO>();
約 定的最后一個(gè)要點(diǎn)是:如果要讓 getDTO() 方法與實(shí)體關(guān)聯(lián),一種方法就是為返回 <Entity>DTO 的實(shí)例的方法將保留此方法名稱,該 DTO 包含關(guān)聯(lián)的實(shí)體的所有非標(biāo)量屬性(這些屬性的最大基數(shù)為 1)。您的團(tuán)隊(duì)可能選擇使用另一個(gè)約定,只要確保一致性即可。
-
假設(shè)需要來自多個(gè)實(shí)體(如客戶、延期交貨訂單、訂單中的產(chǎn)品)的數(shù)據(jù),哪個(gè)實(shí)體應(yīng)“擁有” get<ComposedDTO>() 方法?
要從定義實(shí)體 EJB 上的復(fù)合 DTO 方法的角度回答這個(gè)問題,就要涉及到面向?qū)ο蟮脑O(shè)計(jì)的最佳實(shí)踐。我們?cè)趯谖恼? 使實(shí)體 EJB 組件滿足需求,第 2 部分 中簡(jiǎn)單討論了 OO 委托。對(duì)實(shí)體的選擇取決于實(shí)體與要返回的數(shù)據(jù)之間的關(guān)系。通常,需要選擇可以根據(jù)需要委托到其他實(shí)體以組成完整結(jié)構(gòu)的實(shí)體。在您所給出的具體例子中,您希 望 DTO 返回來自客戶、延期交貨訂單、訂單中的產(chǎn)品(由一個(gè) Line Item 表示,其中包含數(shù)量和總數(shù)的鏈接屬性)的數(shù)據(jù)。讓我們暫時(shí)假設(shè)圖 1 中的類關(guān)系圖描述了業(yè)務(wù)對(duì)象及其相互關(guān)系。
圖 1. 顯示實(shí)體及關(guān)系的示例類關(guān)系圖
對(duì) 于您的示例,“擁有”復(fù)合 DTO 方法的實(shí)體理所當(dāng)然應(yīng)該是 Customer,因?yàn)樗軌蛭械?Order,而后者能夠委托到 Line Item,Line Item 又能委托到 Product。對(duì)于 Customer 實(shí)體上的方法名稱,可以選擇與 getCustomerOpenOrderDetails() 類似的名稱:。
關(guān)系圖上顯示的關(guān)系啟用了多個(gè)路徑,我們可以通過這些路徑檢索組成所有四個(gè)實(shí)體類型的信息的 DTO。例如:
- 給定一個(gè)客戶,檢索延期交貨訂單的詳細(xì)信息(上面所描述的)。
- 給定一個(gè)客戶,檢索所有相關(guān)訂單的詳細(xì)信息。
- 給定一個(gè)訂單,檢索其客戶和詳細(xì)信息。
- 給定一個(gè)行式項(xiàng)目,檢索其相關(guān)的產(chǎn)品,包含此行式項(xiàng)目的訂單和客戶。
- 給定一個(gè)產(chǎn)品,檢索所有相關(guān)的訂單行式項(xiàng)目和客戶。
擁有方法的實(shí)體在上面的“given a(n) <Entity>”子句中指示,它表示起始點(diǎn),因此假設(shè)如下:任何與此方法關(guān)聯(lián)的服務(wù)外觀(或 EJB home 方法)都將采用能標(biāo)識(shí)用于開始委托的一個(gè)或多個(gè)實(shí)體類型的參數(shù)。希望這能夠回答您的第二個(gè)問題。
-
當(dāng)建議從實(shí)體 EJB 返回 DTO 的同時(shí)建議使用本地接口,是否是在“喊狼來了”(以犧牲可維護(hù)性為代價(jià)換取性能的提高)?
在 EJB 1.x 的早期,我們也進(jìn)行過與此類似的有趣的得失分析。我們發(fā)現(xiàn)對(duì)于從實(shí)體返回?cái)?shù)據(jù),存在兩種極端方法和一種中立方法,從而得到三種基本的訪問方式:
-
一次一個(gè)屬性
從 表面上看,可維護(hù)性最好的方法就是完全避免 DTO,而采用一次從客戶機(jī)獲取一個(gè)屬性的方法。但這卻是以減少消息數(shù)目和大小為代價(jià)獲得可維護(hù)性。一般用例將以許多小消息結(jié)束,當(dāng)涉及到遠(yuǎn)程接口時(shí),端 到端通信開銷會(huì)對(duì)響應(yīng)時(shí)間和吞吐量造成很大的影響。另一個(gè)不足(正如您所提到的)就是,還破壞了封裝。破壞了封裝會(huì)對(duì)可維護(hù)性造成負(fù)面影響。例如,如果決 定將一組屬性構(gòu)造到相關(guān)實(shí)體中,將需要更改使用這些屬性的每個(gè)客戶機(jī)! -
一個(gè)大小適合所有 DTO
另 一種極端的方法就是返回與在 DTO 中返回的目標(biāo)實(shí)體關(guān)聯(lián)的所有非標(biāo)量數(shù)據(jù),正如我們?cè)诨卮鸬谝粋€(gè)問題時(shí)所討論的。在這種情況下,您最小化了遠(yuǎn)程消息的數(shù)目,同時(shí)仍然具有相對(duì)的可維護(hù)性。只 對(duì)每個(gè)實(shí)體調(diào)用一次,并一次獲取所有能獲得的全部數(shù)據(jù)。這樣您只得為每個(gè)實(shí)體開發(fā)一個(gè) DTO 和一個(gè)檢索方法。當(dāng)然,折衷方案是 DTO 中包含的數(shù)據(jù)幾乎始終多于給定工作單元所需的數(shù)據(jù),在通常具有很多屬性的實(shí)際實(shí)體中更是如此。因此,此方法對(duì)為每個(gè)工作單元從后端數(shù)據(jù)系統(tǒng)檢索和傳輸?shù)臄?shù) 據(jù)量有很大的影響。這種方法的好處在于,當(dāng)每次添加或刪除屬性時(shí),只需要修改 DTO 即可。而只有客戶機(jī)使用已刪除的屬性時(shí)才需要對(duì)其進(jìn)行修改。 -
自定義 DTO
中 立方法(EJB 倡導(dǎo)者想起了《金發(fā)姑娘與三只熊》的故事)就是對(duì) DTO 結(jié)構(gòu)進(jìn)行定制,使其準(zhǔn)確返回您所需要的數(shù)據(jù)。一次調(diào)用。大小合適。真不錯(cuò)。但問題在于,您必須對(duì)用例進(jìn)行仔細(xì)的分析,以獲得恰當(dāng)?shù)囊唤M DTO 和方法。當(dāng)實(shí)現(xiàn)用例的新類時(shí),必須創(chuàng)建一個(gè)新的 DTO,并調(diào)整 EJB 以對(duì)其進(jìn)行檢索。
當(dāng)使用 EJB 1.x 實(shí)體時(shí),選項(xiàng) c 被認(rèn)為是最好的,因?yàn)榉植际綄?duì)象應(yīng)用程序設(shè)計(jì)主要就是為了盡可能減少調(diào)用(可能為遠(yuǎn)程調(diào)用)的數(shù)量。選項(xiàng) b 是一個(gè)不錯(cuò)的折衷辦法,能獲得一定的可維護(hù)性。這樣一來,就變得更簡(jiǎn)單了,再?zèng)]有煩人的 CMR,也不用考慮“依賴對(duì)象”(屬性的集群,實(shí)際表示“包含”在實(shí)體中的對(duì)象)以外的東西。
但現(xiàn)在已經(jīng)推出了具有本地接口 的 EJB 2.x 和 CMR,我曾想過選項(xiàng) a 是不是最佳的方法(我們剛在專欄文章 Making entity EJB components perform, Part 1 (LINK) 中提到過這個(gè)問題)——但我們始終認(rèn)為,出于同樣的性能原因(盡管它們可能不那么重要),使用選項(xiàng) c 中描述的自定義 DTO 仍然是最好的。我們還指出,由于很多人都已經(jīng)習(xí)慣了 EJB 1.x“最佳實(shí)踐”,比起對(duì)他們進(jìn)行重新培訓(xùn)而言,這更簡(jiǎn)單(而且這也使轉(zhuǎn)換變得更容易)。
-
一次一個(gè)屬性
希望這會(huì)對(duì)您有所幫助,
您的 EJB 倡導(dǎo)者
親愛的 EJB 倡導(dǎo)者:
我理解并同意您對(duì)前兩個(gè)問題的回答。這讓我受益非淺。關(guān)于您對(duì)我的第三個(gè)問題的分析,我的理解是,為什么您認(rèn)為對(duì)于 EJB 1.x,從性能的角度而言,選項(xiàng) c 最佳,但您并沒有真正回答如果使用 EJB 2.x 如何解決可怕的可維護(hù)性問題。
回顧一下您的回信中的簡(jiǎn)單關(guān)系圖。有五種不同的“頂級(jí)”方法對(duì)來自所有四個(gè)實(shí)體的信息加以組合。您沒有提到與每個(gè)實(shí)體關(guān)聯(lián)的,處理委托的方法。讓我們看一看與從客戶獲取延遲交貨訂單關(guān)聯(lián)的方法:
- 給定一個(gè)訂單,返回該訂單和帶產(chǎn)品的行式項(xiàng)目。這將委托給:
- 給定一個(gè)行式項(xiàng)目,返回該行式項(xiàng)目和產(chǎn)品,這將委托給:
- 給定一個(gè)產(chǎn)品,返回其 DTO。
那么,存在不包括所有四個(gè)實(shí)體的組合。僅從客戶來看,就可以提出三種以上的方法:
- 只從客戶返回?cái)?shù)據(jù)。
- 僅返回客戶和延期交貨訂單(不含詳細(xì)信息)。
- 返回客戶和所有相關(guān)的訂單(但也不含詳細(xì)信息)。
現(xiàn)在,將所有這些添加到從每個(gè)實(shí)體獲取部分屬性的排列中??傊?,這種組合非常多,尤其在考慮到(如您自己所說)通常存在更多與每個(gè)實(shí)體關(guān)聯(lián)的屬性時(shí),更是如此。
因此,我不甚明白的第三個(gè)問題是,您似乎以大量的可維護(hù)性為代價(jià),獲得現(xiàn)在的少量性能改進(jìn)。
先行謝過,但我仍然必須簽上這個(gè)名字:
Never Cry Wolf
數(shù)據(jù)傳輸對(duì)象與視圖關(guān)聯(lián)
親愛的 Never Cry Wolf:
開 個(gè)玩笑,現(xiàn)在是您在喊“狼來了”。您不大可能在自定義開發(fā)的應(yīng)用程序中看到很多此類置換。為了理解我這樣講的原因,讓我們從頂層——用例著手。盡管本文不 是關(guān)于進(jìn)行面向?qū)ο蠓治龊驮O(shè)計(jì)的方法的完整教程,但我們?nèi)詫⒑?jiǎn)單了解一些主要構(gòu)件,以說明排列的數(shù)量相對(duì)來說是有限的。
圖 1 的類關(guān)系圖中顯示的實(shí)體與訂單管理業(yè)務(wù)流程相關(guān)聯(lián)。該流程可以使用狀態(tài)轉(zhuǎn)換圖 (STD) 進(jìn)行描述,如圖 2 中所示,其顯示了受管理的單個(gè)訂單的生命周期的各個(gè)階段。
圖 2. 顯示訂單的生命周期的示例狀態(tài)轉(zhuǎn)換圖

順便說一下,僅供參考,圖 2 使用 UML Actor 表示法進(jìn)行了擴(kuò)展,以顯示在給定狀態(tài)中實(shí)例的所有者。我們使用這個(gè)簡(jiǎn)單的擴(kuò)展已經(jīng)多年了,將此作為組織用例并將其綁定到業(yè)務(wù)流程的方法(事實(shí)上,我們喜歡開玩笑地稱用例關(guān)系圖就是一個(gè)尚未“孵出”的狀態(tài)轉(zhuǎn)換圖)。
我 們采用的另一個(gè)略微不同尋常的方法就是為生命周期模型中的每個(gè)狀態(tài)開發(fā)一個(gè)類關(guān)系圖,以顯示對(duì)保持在該狀態(tài)中的屬性和關(guān)系的約束。這些不斷更改的約束在不 考慮狀態(tài)的“單態(tài)”類關(guān)系圖中容易丟失。例如,圖 1 中的類關(guān)系圖顯示的是保持在圖 2 所示的生命周期的開放狀態(tài)中的關(guān)系和屬性。處于已提交狀態(tài)的訂單的類關(guān)系圖可能與圖 3 類似。
圖 3. 顯示處于已提交狀態(tài)的訂單的示例類關(guān)系圖

該 方法按照各個(gè)狀態(tài)提供獨(dú)立的類關(guān)系圖,說明了為什么圖 3 和圖 1 中的類名使用了 [] 來指示狀態(tài),并將“動(dòng)態(tài)”狀態(tài)轉(zhuǎn)換模型和“靜態(tài)”類關(guān)系圖綁在一起。通過比較圖 1 和圖 3,可以很容易發(fā)現(xiàn)隨著 Order 的狀態(tài)在業(yè)務(wù)流程中由開放進(jìn)入已提交狀態(tài)(如圖 2 所示),其“形狀”發(fā)生了更改。圖 2 中的狀態(tài)顯示了行為的更改。
靜態(tài)模 型和動(dòng)態(tài)模型相一起定義了面向服務(wù)的體系結(jié)構(gòu)中完整的服務(wù)集。生命周期模型中的每個(gè)狀態(tài)都可以一對(duì)一地映射到會(huì)話 EJB 組件。STD 中的每個(gè)轉(zhuǎn)換都映射到與狀態(tài)關(guān)聯(lián)的會(huì)話 Bean 上的方法。關(guān)系模型中的每個(gè)類均可以映射一個(gè)實(shí)體 EJB 組件。關(guān)系圖中的關(guān)系自然映射到 CMR。因此對(duì)于開放和已提交兩種狀態(tài),可以推斷出將有兩個(gè)會(huì)話 EJB,而這兩個(gè)會(huì)話 EJB 分別具有三四種更新方法。對(duì)于所顯示的兩個(gè)類關(guān)系圖,可以推斷出將有 15 個(gè)實(shí)體 EJB 組件,具有許多屬性和 CMR。
為了具體一些,讓我們以延期交貨訂單狀態(tài)為例進(jìn)行說明。首先我們編寫一個(gè)純 Java 接口,可以在整個(gè)過程中重用此接口,如下所示:
代碼段 3. 顯示派生于 STD 的方法的純 Java 接口
|
此接口可以在會(huì)話 EJB 接口和類似于以下的實(shí)現(xiàn)中重用:
代碼段 4. 會(huì)話 Bean 接口和實(shí)現(xiàn)類
|
如 果希望,您可以使用 EJB Home 方法代替會(huì)話 EJB。在這種情況下,Customer 實(shí)體就成了業(yè)務(wù)邏輯理所當(dāng)然的“網(wǎng)關(guān)”,因?yàn)樗硎镜氖窃谠摖顟B(tài)中驅(qū)動(dòng)業(yè)務(wù)流程的 Actor。在這種情況下,可以采用上面處理會(huì)話的方式僅擴(kuò)展同一個(gè) OpenOrder 接口,如以下代碼段所示:
代碼段 5. 重用 OpenOrder 接口的 Customer 實(shí)體 Home 接口
|
無論選擇哪種方法,這些模型和映射都能提供實(shí)現(xiàn)更新方法所需的組件。如果要一一提供您的分析中列舉的每種排列,則也可以將這些動(dòng)態(tài)和靜態(tài)的模型用于派生所有的讀取方法。但我們發(fā)現(xiàn),最好從交付支持調(diào)用業(yè)務(wù)流程函數(shù)所需的數(shù)據(jù)的用戶界面 (UI) 屏幕流派生這些讀取方法。
對(duì) 于為屏幕流編寫文檔,我們也希望使用狀態(tài)轉(zhuǎn)換圖。可以將屏幕流 STD 看作是捕獲在業(yè)務(wù)流程模型中擁有狀態(tài)的 Actor 的典型“會(huì)話”的生命周期。其中的狀態(tài)顯示屏幕和彈出對(duì)話框,而轉(zhuǎn)換顯示用戶啟動(dòng)的事件。為了加以說明,圖 4 演示了客戶的一個(gè)屏幕流,顯示它如何與訂單管理流程進(jìn)行交互。
圖 4. 客戶訂單管理會(huì)話的示例屏幕流

模型間的交互(如果有)在轉(zhuǎn)換上的 {} 內(nèi)指定,顯示對(duì)業(yè)務(wù)流程調(diào)用轉(zhuǎn)換時(shí)的副作用。某些事件(如提交)會(huì)進(jìn)入一個(gè)確認(rèn)對(duì)話狀態(tài)。只有用戶觸發(fā)了“OK”,才會(huì)實(shí)際出現(xiàn)提交訂單的副作用。這些確認(rèn)狀態(tài)用斜體表示。
另 一個(gè)用斜體顯示的狀態(tài)就是“Home”狀態(tài),該狀態(tài)表示角色(本例中為 Customer)如何啟動(dòng)和結(jié)束其會(huì)話。還有一個(gè)用斜體顯示的特殊狀態(tài)與業(yè)務(wù)流程相關(guān)聯(lián)——因?yàn)榻o定的 Actor 可能與多個(gè)流程交互。這兩個(gè)狀態(tài)都很特殊,因?yàn)樗鼈冎贿M(jìn)行導(dǎo)航(它們通常以菜單或選項(xiàng)卡的形式出現(xiàn),具體取決于 UI 的樣式)。
其 他的狀態(tài)都表示“實(shí)際”的屏幕(或屏幕的一部分;由于這已經(jīng)涉及到一般 J2EE 最佳實(shí)踐,所以我們將在另一篇文章中專門就此進(jìn)行討論)。對(duì)于每個(gè)屏幕(不管是否為特殊屏幕),都可以使用類關(guān)系圖捕獲該狀態(tài)的可見數(shù)據(jù),類似于和業(yè)務(wù)流 程關(guān)聯(lián)的類關(guān)系圖顯示與狀態(tài)關(guān)聯(lián)的持久數(shù)據(jù)的方式。圖 5 顯示除確認(rèn)狀態(tài)之外的所有狀態(tài)的組合類關(guān)系圖。
圖 5. 顯示會(huì)話的可見數(shù)據(jù)的示例類關(guān)系圖

現(xiàn) 在我們就能理解為什么不會(huì)有很多 DTO 和相關(guān)方法的原因了。圖 5 顯示了七個(gè)包含內(nèi)容(關(guān)系計(jì)數(shù))的 DTO。這些 DTO 非常直接地映射到 Java 類。圖 4 所示的屏幕流上的到某個(gè)狀態(tài)的轉(zhuǎn)換映射到 OpenOrder 上的其他方法。它們所返回的 DTO 在圖 5 的類關(guān)系圖中進(jìn)行了描述。我們要使用的約定是 <TargetState>Data(而非 DTO)。此方法的參數(shù)作為與轉(zhuǎn)換關(guān)聯(lián)的數(shù)據(jù)流顯示;其名稱將成為方法名的一部分。代碼段 6 顯示了某些示例:
代碼段 6. 某些從 UI 派生的只讀方法
|
正 如您所看到的,只讀方法非常少?!案盌TO 的數(shù)目甚至更少,因?yàn)檫@些 DTO 被重用。最糟糕的情況下,此例中也僅需八個(gè) DTO 支持業(yè)務(wù)流程。而且,即使在實(shí)體 EJB 組件中進(jìn)行 OO 委托以加載完整的結(jié)構(gòu),get<DTO>() 方法的總數(shù)仍將相對(duì)較少。
很抱歉,為了回答一個(gè)相對(duì)簡(jiǎn)單的問題,我講了這么一大堆關(guān)于常規(guī) OO 分析和設(shè)計(jì)技術(shù)的話題,但我仍然認(rèn)為在實(shí)際操作中,通過返回需要的數(shù)據(jù)結(jié)構(gòu)所帶來的封裝優(yōu)勢(shì)會(huì)超過相關(guān)維護(hù)問題的困擾。
您同意嗎?
好,就此打住,
您的 EJB 倡導(dǎo)者
.
![]() |
親愛的 EJB 倡導(dǎo)者:
您進(jìn)行面向?qū)ο蟮姆治龊蛯⒐ぷ鞒晒成涞?EJB 組件的方式很有意思。您的方法讓我相信可維護(hù)性問題并非想象的那樣糟。但我還有一個(gè)問題想請(qǐng)教。
我 仔細(xì)考慮之后,得出了一個(gè)完全不同的問題:如果調(diào)用 CMP 的 get<attribute>() 方法完全沒有性能損失,您是否仍然會(huì)建議會(huì)話外觀、DTO 裝配器或?qū)嶓w Home 方法對(duì)實(shí)體使用 get<DTO>() 方法,而不直接一次性從相關(guān)實(shí)體獲得其所需的屬性?
例如,以圖 5 中的 DetailItemData DTO 為例。我認(rèn)為,如果我按照您的建議使用 OO 委托,LineItem 實(shí)體將具有一個(gè) getDetailItemData() 方法。此方法將按照 CMR 的指引獲得對(duì) Product 的引用。您建議不對(duì) Product 調(diào)用 getDescription() 和 getPrice(),而是創(chuàng)建一個(gè)新的 ProductDescriptionAndPriceData 對(duì)象,并對(duì) Product 調(diào)用 getProductDescriptionAndPriceData()。然后我將從此結(jié)構(gòu)中復(fù)制字段,并將這些字段和 productId 與 quantity(以及計(jì)算得到的量)一并復(fù)制到 DetailItemData 結(jié)構(gòu)中。
我覺得這個(gè)方法真的很多余,除非性能真的有那么糟糕。
盼復(fù),
Never Cry Wolf
親愛的 Never Cry Wolf:
您堅(jiān)持不懈(沒有別的意思)的詢問真的讓 EJB 倡導(dǎo)者不禁懷疑自己倡導(dǎo)使用 EJB 的力度是否不夠。
我 必須承認(rèn),如果對(duì)本地實(shí)體 EJB 組件使用 get<attribute>() 方法,沒有任何性能問題,您所采用的在外觀或?qū)嶓w Home 方法或已委托的方法中組裝所需數(shù)據(jù)的方法更具吸引力。這個(gè)方法在生成時(shí)要編譯的組件數(shù)量更少,運(yùn)行時(shí)要回收的垃圾也更少,因此,我很高興您相信了您的直 覺,認(rèn)為真正的問題并沒有得到回答。我們之間的這幾番交流表明,有時(shí)候必須反復(fù)多次才能徹底了解問題的實(shí)質(zhì)。
另一方面,我也曾有 個(gè)直覺,認(rèn)為本地方法調(diào)用的性能影響仍然很可觀。但我沒有采用任何有意義的方式進(jìn)行測(cè)試,以驗(yàn)證這個(gè)想法,而是相信那句格言“if it ain't broke, don't fix it”(東西還沒壞,就別急著去修它)——不僅是因?yàn)檫M(jìn)行性能測(cè)試非常麻煩,而且也由于修改所有關(guān)于最佳實(shí)踐的演示材料和現(xiàn)有示例比這更麻煩。
這句格言對(duì)于“早期的”應(yīng)用程序非常合理,但能驗(yàn)證我原來的直覺則更好,因?yàn)樾麻_發(fā)項(xiàng)目可以在適當(dāng)?shù)那闆r下選擇適當(dāng)?shù)姆椒ā?
因 此,我讓一個(gè)團(tuán)隊(duì)進(jìn)行了性能測(cè)試,結(jié)果我很驚喜地發(fā)現(xiàn),只要客戶機(jī)和實(shí)體均位于同一個(gè)全局事務(wù)范圍內(nèi),“客戶機(jī)”通過本地接口調(diào)用本地 get<Attribute>() 方法和讓實(shí)體 Bean 實(shí)現(xiàn)調(diào)用自身抽象的 get<Attribute>() 方法,這兩種方式之間并沒有明顯的區(qū)別。
有了這個(gè)新數(shù)據(jù)后,我非常高興地對(duì)我的方法進(jìn)行了修改,如果尚沒有提供信息的現(xiàn)有 get<DTO>() 方法,則直接使用 get<Attribute>() 方法組裝所需的數(shù)據(jù)。這適合于實(shí)體 EJB、實(shí)體 Home 方法、會(huì)話外觀或(如您所稱) DTO 裝配器類上的已委托的方法。
我還十分高興地發(fā)現(xiàn),居然有人比我還更像一個(gè) EJB 倡導(dǎo)者!如果有機(jī)會(huì)見面的話,我一定會(huì)請(qǐng)您吃飯。
好,就此打住,
您的 EJB 倡導(dǎo)者
.
下面是從以上討論中得出的一些有意義的原則:
- 您的分析工作成果應(yīng)該同時(shí)涵蓋業(yè)務(wù)域和用戶界面的動(dòng)態(tài)和靜態(tài)方面。
- 系統(tǒng)地將您的分析工作成果映射到適當(dāng)?shù)?EJB 組件和 DTO。
- 會(huì)話 Bean 非常適合實(shí)現(xiàn)與業(yè)務(wù)流程(更新)或屏幕流(讀?。┲械臓顟B(tài)關(guān)聯(lián)的轉(zhuǎn)換。
- 當(dāng)與表示擁有一個(gè)或多個(gè)業(yè)務(wù)流程中的狀態(tài)的 Actor 的“網(wǎng)關(guān)”對(duì)象關(guān)聯(lián)時(shí),實(shí)體 Bean Home 方法是最好的選擇。
- 在兩種情況下,都要盡可能利用與網(wǎng)關(guān)對(duì)象關(guān)聯(lián)的 CMR,并根據(jù)需要使用 get<DTO>(OO 委托)或 get<Attributes>(過程型組裝),以獲取要返回的數(shù)據(jù)。這很大程度上取決于您是否已經(jīng)擁有適當(dāng)?shù)?DTO。
- 最后,EJB 倡導(dǎo)者愿意承認(rèn)自己錯(cuò)了。只是要認(rèn)識(shí)到自己的錯(cuò)誤可能還需要一些時(shí)間。
我們相信您還能夠找到更多的類似問題。在下一篇專欄文章推出之前,這就夠您忙活的了。
在此特別感謝 Bobby Woolf,他為本文提供了重要的建議和資料。請(qǐng)?jiān)L問 Bobby 的博客來了解 J2EE in Practice 。
-
您可以參閱本文在 developerWorks 全球站點(diǎn)上的
英文原文
。
-
Java 2 Platform, Enterprise Edition (J2EE) 規(guī)范
(最可靠的來源)
- 由 Martin Fowler 作序言,Kyle Brown、Gary Craig、Greg Hester、Russell Stinehour、W. David Pitt、Mark Weitzel、JimAmsden、Peter M. Jakab 和 Daniel Berg 合著的 Enterprise Java Programming with IBM WebSphere, Second Edition 。
![]() |
||
![]() |
Geoff Hambrick 來自 Texas 的 Round Rock(在 Austin 附近),是 IBM Software Services for WebSphere Enablement Team 的首席顧問。Enablement Team 通常通過深層技術(shù)簡(jiǎn)報(bào)及短期概念驗(yàn)證為售前流程提供支持。Geoff 于 2004 年 3 月被選為 IBM 的杰出工程師 (Distinguished Engineer),他的工作是創(chuàng)建并傳播用于開發(fā) IBM WebSphere A |
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
