文章詳情頁
Session Facade 的規(guī)則和模式
瀏覽:17日期:2024-07-20 18:32:15
內(nèi)容: Kyle Brown Java 執(zhí)行設(shè)計師,IBM WebSphere Service 2001 年 6 月 在過去幾年中,Enterprise JavaBeans™(EJB)確實已經(jīng)開始對 Java™ 對象設(shè)計產(chǎn)生影響。期間,我們看到的最常使用的 EJB 模式之一是Session Facade 概念。這是一個讓很多開發(fā)者都受益匪淺的既強大又非常簡單的概念。然而,我也看到,對這一模式的確切含義及其在實踐中的應(yīng)用,人們?nèi)杂泻芏嗾`解。 為了把這個問題講得更明白些,我會在本文中講述 Facade 的一些基本概念以及Session Facade 模式的工作機制,并探討該模式衍生出來的一些問題。希望能借此澄清一些誤解,并幫助開發(fā)者正確使用這種模式。 什么是Session Facade?您又為什么需要它? 很多地方都有對Session Facade 模式的清楚描述,也就是 [Sun 2001] 和 [Brown 2000]。我不想照抄那里的全部內(nèi)容,而打算把它的理論在此作個總結(jié):基本的問題是在 EJB 設(shè)計中,EJB 客戶機(例如,Servelet、Java 應(yīng)用程序,等等)不可直接訪問 Entity bean。 之所以如此,有以下幾個原因: 當依靠 RMI-IIOP 進行跨越網(wǎng)絡(luò)的調(diào)用時運行態(tài)的性能會受到極大影響。如果客戶機請求一個Entity bean 去表示如包含兩項數(shù)據(jù)(比方說帳戶余額和帳戶所有者姓名)的銀行帳戶,則將需要兩個網(wǎng)絡(luò)調(diào)用。當大量屬性使網(wǎng)絡(luò)調(diào)用成倍增加時,很快這些開銷就會變得非常明顯。[Monson-Haefel] 中所說的批量訪問器(bulk accessors)或許是一種解決方案,所謂批量訪問器,就是Entity bean 上的一些方法,它們創(chuàng)建并返回值對象以表示Entity bean 中的數(shù)據(jù)。它事實上就是 Java VisualAge® 的 CopyHelper Access Beans 采用的解決方案。但是,它有一個令人遺憾的缺陷,就是它假設(shè)所有的請求都需要 EJB 中的“所有數(shù)據(jù),結(jié)果為用戶返回了一些不必要的數(shù)據(jù),并導(dǎo)致對更大的值對象進行組織和分解時產(chǎn)生額外開銷。 更重要的是,如果您允許 EJB 客戶機直接訪問Entity bean,那么就要求客戶機了解Entity bean 的內(nèi)部方法,而這已經(jīng)超出了客戶機的應(yīng)知的范圍。例如,操作一個Entity bean 需要知道所涉及到的該實體的關(guān)系(關(guān)聯(lián),繼承),這樣就把業(yè)務(wù)模型的所有細節(jié)不適當?shù)乇┞督o了客戶機。另外,操作多個Entity bean 會要求使用客戶端事務(wù) ? 這是另一個使事情復(fù)雜化的因素,這意味著 EJB 可能要被從客戶機設(shè)計中除去,而不是添加上去。 大多數(shù)設(shè)計師已經(jīng)發(fā)現(xiàn)為了在 EJB 設(shè)計中避免直接訪問Entity bean 的解決方案都可以在 Gamma 中描述的 Facade 中找到。 Gamma 這樣描述 Facade 模式:“為子系統(tǒng)中的一套接口提供了一個統(tǒng)一的接口。Facade 定義了一個更高層次的接口,使子系統(tǒng)更容易使用。1在 EJB 中應(yīng)用這種思想一般意味著您應(yīng)該創(chuàng)建一個擔當 Facade 的Session EJB,然后把構(gòu)成子系統(tǒng)的一套Entity bean “包裝起來。這樣,客戶機就和Entity bean 實現(xiàn)的細節(jié)分離開來了,而且不必自己管理事務(wù)管理的細節(jié)。 但問題是有很多人到此就打住了。然后他們輕松地往下做,開始把Entity bean 包裝到Session bean 中,而不考慮 Facade 模式所描述的其它內(nèi)容以及 EJB 設(shè)計中由 Facade 模式衍生出來的問題。這很可能是由于把得到的 Facade 的“二手信息都當真,而沒去研究原始模式的緣故。如果我們確實花了些時間去理解 Facade 衍生的問題,我們將可以看到很多該模式所固有的其它有益的設(shè)計可能性。 Facade 模式的要點 Gamma 中描述了很多我們應(yīng)該了解的 Facade 模式的要點。前面幾點可在 Facade 模式的“適用性描述部分找到,它描述了在什么情況下您會需要應(yīng)用該模式。它們是:“當您想為復(fù)雜的子系統(tǒng)提供一個簡單接口時……請使用 Facade 模式和“當您想把子系統(tǒng)分層時……請使用 Facade 模式。使用 Facade 為每一層子系統(tǒng)定義一個入口點。2 從對 Facade 模式的討論中,我們可以提煉出兩個觀點。第一點是 Facade 應(yīng)該提供子系統(tǒng)的一個抽象視圖,而不是簡單地把整個子系統(tǒng)本身的 API 直接包裝起來。不幸的是,我在實際中多次看到開發(fā)者創(chuàng)建的Session bean 把Entity bean home 和Entity bean 對象的全部方法直接包裝起來,而不提供任何額外的抽象,這是對該模式最可惡的濫用情況之一。請記住,這種思想是想降低整個系統(tǒng)的復(fù)雜性,而不是把復(fù)雜性轉(zhuǎn)移到另一個對象上。 第二點,也是更微妙的一點,與分層有關(guān)。這個觀點認為您可以用多重 Facade 來隱藏下層子系統(tǒng)的細節(jié)。因此,在這里您可以這樣設(shè)想,Session Facade 應(yīng)該在其它 Facade 之上,位于最上層,是對底層業(yè)務(wù)邏輯細節(jié)的進一步抽象。這一點很關(guān)鍵。當您看完下面兩條(分別出自 Gamma 中論述 Facade 模式的“協(xié)作和“相關(guān)模式部分)敘述后,就會更加清楚這一點: “客戶機通過把請求發(fā)送給 Facade,再由 Facade 把請求轉(zhuǎn)發(fā)給適當?shù)淖酉到y(tǒng)對象來與子系統(tǒng)通信。3 “facade 只是對通往子系統(tǒng)對象的接口進行抽象以使它們更易于使用;它不定義新功能。4 我把這幾點總結(jié)如下:Facade 不做系統(tǒng)的實際工作;而是委托其他對象輪流做這個工作。由此推理出您必須正確地放置這些對象,以便使該模式能按照您所期望的運行。 這一點是本模式的兩種流行表達 [Sun 2000] 和 [Sun 2001] 之間的主要不同之處。第一個版本,即 [Sun 2000],是 J2EE 規(guī)劃的一部分,它把這種模式稱為“Session Entity Facade。它意在表明“為一堆企業(yè) beans 提供單一的接口。它描述了這樣一種模式,即所有的數(shù)據(jù)存取都通過Entity bean 來完成,Session bean 則為這些Entity bean 提供接口。現(xiàn)在的問題是 [Sun 2000] 不一定非要以 EJB 為中心。它根本不涉及其它對象類型,并且假設(shè)系統(tǒng)中只有 EJB 一類對象。根據(jù)我的經(jīng)驗,我認為這會導(dǎo)致根本不能在工程間重用的臃腫的Session對象,而且,在同一個工程內(nèi),當需求有一點不同時就會出現(xiàn)問題。 現(xiàn)在,[Sun 2001] 則更通用,也沒有上述問題的困擾。它簡單地把這種模式稱為“Session Facade。它的解決方案規(guī)定您應(yīng)該“把Session bean 當作 facade 來用,以封裝參與工作流的業(yè)務(wù)對象之間的交互操作的復(fù)雜性。它根本不限制您的業(yè)務(wù)對象應(yīng)該為 EJB,因此是一個更加靈活的方法。 Session Facade 的重要規(guī)則 那么我們該如何應(yīng)用這些關(guān)于針對會話的 Facade 的規(guī)則呢?這對我們的 EJB 設(shè)計又意味著什么呢?我在設(shè)計Session Facade 時遵循三條基本原則: 它們自己不做實際工作;它們委派其它對象做實際工作。這意味著Session facade 中的每個方法都應(yīng)該很小(異常處理邏輯不計算在內(nèi),代碼應(yīng)為五行或更少)。 它們提供簡單的接口。這意味著 facade 方法的數(shù)量應(yīng)相對較少(每個Session bean 中僅有約 24 個)。 它們是底層系統(tǒng)的客戶端接口。它們應(yīng)該把特定于子系統(tǒng)的信息封裝起來,并且不應(yīng)該在不必要的情況下公開它。 那么它的工作機制呢?您還能代理別的哪些類型的對象呢?這又會給您的設(shè)計帶來什么好處呢?在我的一篇早期論文和 [Brown 2001] 這本書中,我已論述了其中一些問題,在那里可以找到一些詳細信息。但,總的來說,在我的多數(shù) EJB 設(shè)計中我通常會找到以下四類對象: 值對象是包含了客戶機所請求的數(shù)據(jù)的、可序列化的 Java bean。它包含Entity bean 和其他數(shù)據(jù)源所包含的數(shù)據(jù)的一個子集。它是Session EJB 方法的返回類型。[EJB 2.0] 和 [Sun 2001] 都描述了值對象和值對象的用途。請注意 [Fowler 2001] 稱其為“數(shù)據(jù)傳輸對象( Data Transfer Objects ),[Brown 1999] 也使用這個名稱。我個人覺得數(shù)據(jù)傳輸對象是描述性更好的術(shù)語,但不幸的是,Sun 的術(shù)語似乎更通用。 對象制造廠 (Factory) [Brown 1999] [Brown 2000] 負責構(gòu)建值對象。它能完成辨別不同的數(shù)據(jù)源、創(chuàng)建值對象的實例、填充值對象的實例等等工作。每個 factory 類 都可以從多個數(shù)據(jù)源中檢索數(shù)據(jù)或更新其中的數(shù)據(jù)。在您的對象模型中,每個“根對象都應(yīng)該有一個 factory 類。(根對象是那些“包含其它對象的對象。)從某種意義上說,對象 Factory 類在 JDBC 或持久的 Entity bean 子系統(tǒng)上擔當 Facade,實現(xiàn) Gamma 中提到的分層原則。 Entity EJB 應(yīng)該是標準的、企業(yè)全局范圍內(nèi)可用的“數(shù)據(jù)源。Entity bean 不應(yīng)包含特定于應(yīng)用程序的域邏輯,也不應(yīng)限制為只能在單一應(yīng)用程序內(nèi)工作。請注意Entity bean 是可選的,它不是這種體系結(jié)構(gòu)中必需的部分;Factory 可能像 JMS 隊列或 JDBC 連接那樣簡單地直接從數(shù)據(jù)源獲取數(shù)據(jù)。 Action 對象是Session bean 可能調(diào)用的唯一對商業(yè)業(yè)務(wù)進行處理的對象。Action 對象只處理與簡單的創(chuàng)建、讀取、更新或刪除數(shù)據(jù)無關(guān)的商業(yè)流程。和對象 Factory 一樣,Action 對象也充當內(nèi)層 Facade。 一個 EJB 對象示例 描述類似這樣的模式遇到的一個問題是,能夠使用這種模式的示例都太大,以至于無法包含在模式自身的描述中。盡管如此,我還是要嘗試舉出如下示例(它顯然很簡單)來說明一下這些對象看起來是什么樣子。 假設(shè)我們正在為銀行構(gòu)建一個 ATM 系統(tǒng)。這是最老掉牙的 OO 設(shè)計問題之一,當然其它很多書籍和論文已經(jīng)討論過它,但它確實有足夠符合我們要求的有趣特點。通過分析,我們發(fā)現(xiàn)了兩種 EJB。 從 ATM 到銀行的連接表示為Session bean。該 bean 上有一些方法負責處理您通過 ATM 可以完成的交易 ? 存款、取款以及帳戶間的資金轉(zhuǎn)移。 帳戶表示為Entity bean(我們的示例采用 CMP,但它在我們的示例中實際上并沒什么影響)表示。它有返回帳戶余額、對帳戶進行借貸處理的方法。 ATM Session bean 的遠程接口如下: package com.ibm.bankexample.ejbs; import com.ibm.bankexample.domain.*; /** * This is the Enterprise Java Bean Remote Interface * for the ATM example. */ public interface ATM extends javax.ejb.EJBObject { void deposit(java.lang.String accountNumber, double amount) throws java.rmi.RemoteException, com.ibm.bankexample.domain.FactoryException; java.util.Vector getAccounts(java.lang.String userid) throws java.rmi.RemoteException, com.ibm.bankexample.domain.FactoryException; void transfer(java.lang.String fromAccount, java.lang.String toAccount, double amount) throws java.rmi.RemoteException, com.ibm.bankexample.domain.InsufficientFundsException, com.ibm.bankexample.domain.FactoryException; void withdraw(java.lang.String accountNumber, double amount) throws java.rmi.RemoteException, com.ibm.bankexample.domain.InsufficientFundsException, com.ibm.bankexample.domain.FactoryException; } 同樣地,帳戶 EJB 的遠程接口如下: package com.ibm.bankexample.ejbs; /** * This is the Enterprise Java Bean Remote Interface * for the Account Entity EJB. */ public interface Account extends javax.ejb.EJBObject { void deposit(double amount) throws java.rmi.RemoteException; java.lang.String getAccountNumber() throws java.rmi.RemoteException; double getBalance() throws java.rmi.RemoteException; java.lang.String getUserid() throws java.rmi.RemoteException; void setBalance(double newValue) throws java.rmi.RemoteException; void setUserid(java.lang.String newUserid) throws java.rmi.RemoteException; void withdraw(double amount) throws java.rmi.RemoteException; } 現(xiàn)在,我們還發(fā)現(xiàn)有另外兩種對象類型對我們的系統(tǒng)是有用的。第一種是描述顯示在 ATM 機上的帳戶信息的值對象。這個類看起來如下所示: public class AccountValue implements java.io.Serializable { private java.lang.String accountNumber; private double balance; } 當然,AccountValue 類也有作為屬性的 getter 和 setter 的方法,但我們暫時不考慮它們。 現(xiàn)在,我們基本上有了足夠的信息來理解 ATM EJB 的 getAccounts() 方法的實現(xiàn)。這個方法的實現(xiàn)如下: public java.util.Vector getAccounts(String userid) throws FactoryException { AccountFactory fact = new AccountFactory(); Vector result = fact.getAccounts(userid); return result; } 這個方法展示了Session Facade EJB 的方法的標準模式。它找到合適的幫助對象(Action 或 Factory,在本例中是 Factory),調(diào)用幫助對象上的業(yè)務(wù)方法,然后返回結(jié)果。 如這個方法所指出的,我們需要一個 AccountFactory 類來從 Accounts 構(gòu)建 AccountValues。這個類的類定義如下: public class AccountFactory { private static AccountHome accountHome = null; } AccountFactory 的 getAccounts(userid) 方法的實現(xiàn)如下: public java.util.Vector getAccounts(String userid) throws FactoryException { try { Vector vect = new Vector(); AccountHome home = getAccountHome(); Enumeration accountRefs = home.findByUserid(userid); while (accountRefs.hasMoreElements()) { Account acc = (Account) accountRefs.nextElement(); AccountValue valueObject = new AccountValue(); valueObject.setAccountNumber( acc.getAccountNumber()); valueObject.setBalance(acc.getBalance()); vect.addElement(valueObject); } return vect; } catch (Exception e) { throw new FactoryException( 'Cannot generate accounts due to wrapped exception ' + e); } } 這個方法使用一個高速緩存的 AccountHome 實例,它是從以下方法中獲取的: private AccountHome getAccountHome() { if (accountHome == null) { try { java.lang.Object homeObject = getInitialContext().lookup( 'com/ibm/bankexample/ejbs/Account'); accountHome = (AccountHome) javax.rmi.PortableRemoteObject.narrow( (org.omg.CORBA.Object) homeObject, AccountHome.class); } catch (Exception e) { // Error getting the home interface System.out.println( 'Exception ' + e + ' in createTimeSheetHome()'); } } return accountHome; } 正如 [Brown 2001] 和 [Gunther 2000] 所描述的那樣,在 WebSphere® 中,高速緩存 EJB home 是一個極好的習慣,因為獲取 JNDI InitialContext 和從 InitialContext 獲取 EJB Home 需要一段時間。 既然您已經(jīng)看到了Session、Entity和 Factory 如何組合在一起,那我們就來看一個 Action 類的示例。在本例中,我們有一個處理從一個帳戶到另一個帳戶的資金轉(zhuǎn)移的 Transfer 對象。Transfer 由 ATM EJB 中的 transfer() 方法的實現(xiàn)中創(chuàng)建,該方法的實現(xiàn)如下: public void transfer(String fromAccount, String toAccount, double amount) throws InsufficientFundsException, FactoryException { Transfer trans = new Transfer(); trans.transfer(fromAccount, toAccount, amount); } 請再次注意同樣的流程。不過,這個方法不必從 Action 對象返回值。Transfer 類的定義如下: public class Transfer { private static AccountHome accountHome; } transfer() 方法的實現(xiàn)如下: public void transfer(String fromAccount, String toAccount, double amount) throws InsufficientFundsException, FactoryException { try { Account from = getAccountHome().findByPrimaryKey( new AccountKey(fromAccount)); Account to = getAccountHome().findByPrimaryKey( new AccountKey(toAccount)); if (from.getBalance() < amount) throw new InsufficientFundsException(); to.deposit(amount); from.withdraw(amount); } catch (Exception e) { throw new FactoryException( 'cannot perform transfer. Nested exception is ' + e); } } 您已經(jīng)看到,Transfer 對象中的 transfer() 方法處理以下細節(jié):定位兩個 Account 實體,確保“From帳戶有足夠的余額,把轉(zhuǎn)移金額存入“To帳戶,從“From帳戶中提出轉(zhuǎn)移金額。同樣地,您可以看到 Action 對象的其它方法可以實現(xiàn)您系統(tǒng)中的其它業(yè)務(wù)規(guī)則。 使用 EJB 對象的原因 那么為什么我們需要這第二層對象呢?難道我們從 CORBA 和 RMI 轉(zhuǎn)到 Enterprise JavaBean 就使事情更簡單了嗎?為什么不把所有的邏輯都放到 EJB 中呢?這有幾個原因。第一個也是最重要的原因是這是一個分層應(yīng)用程序。在單個對象中放置太多工作從來不是一個好主意。如果您用這種方式來布置由 EJB 調(diào)用的對象,可以帶來以下好處: 把工作放在一個會話層上的一套對象中,使我們可以更容易獨立地測試它們,或許甚至可以在 J2EE 應(yīng)用服務(wù)器環(huán)境之外對它進行測試。 不同的多個Session Facade 對象可以使用同一層上的對象,而不必擔心事務(wù)語義不正確,也沒有跨Session bean 調(diào)用可能帶來的網(wǎng)絡(luò)和數(shù)據(jù)組織/數(shù)據(jù)分解開銷。 第二層對象允許您對那些對象實現(xiàn)多樣化(通過使用 Gamma 中介紹的 Stragtegy 模式),這樣便可以利用應(yīng)用服務(wù)器的特有功能,同時仍然保持整個設(shè)計在應(yīng)用服務(wù)器之間的可移植性。例如,[Brown 2000a] 描述了一些特別的高速緩存策略,用于提高那些能在 WebSphere Application Server(高級版)下工作、卻不能在 IBM CICS EJB 支持下工作的 EJB 的性能。通過為同一個 Factory 類或 Action 類提供兩個實現(xiàn),您便可以保持整個設(shè)計的可移植性,同時也最大程度地利用各個服務(wù)器的特有功能。 在您不需要 JTA 事務(wù)的情況下(例如,您只對單一數(shù)據(jù)源進行操作),這個模式允許您選擇部署和構(gòu)建帶或不帶 EJB 的應(yīng)用程序。例如,在一些簡單查詢中,為避免 EJB 調(diào)用的開銷,您可以直接從 servlet 調(diào)用 Factory,這能顯著提高效率。 同時,通過回顧幾個工程,我們發(fā)現(xiàn)重用只在少數(shù)情況下會出現(xiàn)在會話層上。這是因為,每個會話都有針對一個特定應(yīng)用程序的一個事務(wù)設(shè)置與方法的特定組合。有了第二層對象則使您可以在內(nèi)層級別上進行重用,我們在很多工程中都看到過這種重用,包括在企業(yè)的一個工程內(nèi)(在不同的Session bean 之間)和多個工程之間。 我們已經(jīng)看到,如果采用這種策略,那么您的設(shè)計經(jīng)常可以把無狀態(tài)Session bean 當作 Facade 對象使用。由于對某個用戶而言,每個無狀態(tài)Session bean 都不是唯一的,這就使您能夠得到無狀態(tài) bean 所提供的另外的可擴展性。 既然我們已經(jīng)知道了 facde 背后對象的類型,我們就可以開始看看 facade 能對外提供哪些類型的方法了。我們看到 Facade 方法通常屬于以下幾種類型: Collector 方法通常以“get開頭,返回一個對象或一個對象集合(在 EJB 1.0 中是 Emulation,在 EJB 1.1 和 2.0 中則是一個 Java Collection)。如 [Brown 2000] 所述,collector 方法在 Factory 對象中實現(xiàn)。 Updater 方法根據(jù)作為參數(shù)傳入的值對象所掌握的信息來定位并更新一個Entity bean 或一個Entity bean 集。方法名稱常常以“update或“set開頭。updater 方法的實現(xiàn)可以像 [Brown 2000] 所說的那樣放在 factory 中,或者在一個單獨的類中。 Action 方法(例如 transfer(String fromAcctNum, String toAcctNum, BigDecimal amount))的實現(xiàn)放在 Action 對象中。 Session Facade 的創(chuàng)建規(guī)則 既然您看到了Session Facade 接口的樣子,在Session Facade 背后的又有哪些對象,那么下一個問題就是“我該有多少Session Facade 呢?您不應(yīng)擁有太多的Session Facade,否則,就喪失了 Facade 模式帶來的好處。但是,若整個應(yīng)用程序?qū)?yīng)一個Session Facade 它可能會成為一個“巨大的對象5并導(dǎo)致它自身的一些問題。這里是設(shè)計Session Facade 的一些規(guī)則,使您能適當?shù)兀ú贿^多或過少)使用它。 從您的應(yīng)用程序中找出功能子系統(tǒng)。例如,名為定單管理、帳單管理和運輸管理的子系統(tǒng)就是一個應(yīng)用程序中可能有的三個 Facade 對象。 回到您的用例(Use-case)和相關(guān)的用例組。一組相關(guān)的用例 (例如購買股票、出售股票和獲取報價)可以形成一個內(nèi)聚子系統(tǒng),例如“股票交易。這個內(nèi)聚子系統(tǒng)就可能要共享很多內(nèi)層對象,并且是使用Session Facade 的最佳候選。[Sun 2001] 更深入地討論了這個問題。 千萬不要把所有的單個用例都做到Session Facade 中。這將導(dǎo)致系統(tǒng)分布截面過大。這種情況下,客戶機將不得不管理非常多的 EJB 引用和 Home。 完成初步工作后,看一下您的設(shè)計中第二層對象之間的關(guān)系。如果您看到有值對象、Factory 和 Action 的不相交組,那就根據(jù)實際分組法把 Facade 分成兩個或更多 facade。 另一種會話模式 既然您已深信應(yīng)該使用無狀態(tài)的Session Facade 來包裝數(shù)據(jù)源,也應(yīng)該在這些 facade 的實現(xiàn)中進行嚴格的分層,您可能會想知道特定于用戶的應(yīng)用程序狀態(tài)(如果有的話)將被保存在什么地方。根據(jù)我所主張的把Session facade 設(shè)計成能處理多用例請求,您可能還會想知道用例在哪里實際實現(xiàn)。 為了理解如何應(yīng)用它,我們采用出自 [Jacobson 1999] 的 Control 對象的如下定義:“Control 類代表協(xié)調(diào)、順序事務(wù)以及對其它對象的控制,常用于封裝與特定用例相關(guān)的控制。 這個解決方案的目標是實現(xiàn)專門的、與一個單一的用例一一對應(yīng)的“用例控制器對象。每個用例控制器都將維護一些特定于用戶的狀態(tài),這些狀態(tài)與判斷一個用戶在此用例中位于哪里所必需的信息(例如,它們已經(jīng)執(zhí)行了多少)相對應(yīng),也與用戶輸入的、對執(zhí)行用例的下一步來說必需的信息相對應(yīng)。這樣,我們就找到了一個能夠用真正不依賴于 GUI 的方式來實現(xiàn)和編寫用例的方案。 那么,實現(xiàn)這些用例控制器對象,您有哪些選擇呢?因為它們天生就必須是有狀態(tài)的,我們有兩個 J2EE 體系結(jié)構(gòu)中自己提供的選擇: 一個選擇是把用例控制器變?yōu)榭尚蛄谢瘜ο螅↗avaBeans),然后在 HttpSession 中存儲和檢索它們。當然,這只能用在使用 Servlet API 的應(yīng)用程序中。但它可以應(yīng)用于很多應(yīng)用程序,甚至包括那些使用 Applet 和 Application 的客戶機 GUI 的應(yīng)用程序,因為即使在這些情況下,通過 HTTP(也可能使用 SOAP)來和服務(wù)器端對象進行通信也是一個常用的設(shè)計策略。用 HttpSession 作為存儲機制會使程序員更輕松,因為在多數(shù)應(yīng)用服務(wù)器(例如 WebSphere)中會話的持久和故障轉(zhuǎn)移細節(jié)都是自動處理的。然而,在 WebSphere 中,一個 HttpSession 要得到合理的持久性,則其大小將受到一定的限制(請參閱 Gunther ),所以這個選擇只適合用例控制器對象相對較小的情況。 另一個選擇是把有狀態(tài)的Session bean 當作用例控制器用。有狀態(tài)的Session bean 是個很好的解決方案,它使程序員不必擔心如何維護會話信息。在有狀態(tài)的Session bean 被自動存儲在共享持久存儲器的應(yīng)用服務(wù)器中,這個解決方案甚至能處理故障轉(zhuǎn)移。但是,在像 WebSphere 這樣的應(yīng)用服務(wù)器中的Session bean 并不存儲在共享持久存儲器中,如果碰上服務(wù)器崩潰,這個解決方案將導(dǎo)致用戶會話失敗。而且,以這種方式使用有狀態(tài)的Session bean 會使我們回到增大總的分布截面的老問題上。盡管如此,由于有狀態(tài)的Session bean 自己充當一個 facade,每個客戶機只需知道少數(shù)的用例控制器,這樣就減輕了這個問題。 繞了個圈,這種模式又把我們帶回到我們最初討論的 Facade 模式。這種模式相繼分層的方式使我們可以集中精力處理手邊的工作,同時還允許我們重用一些東西來構(gòu)成我們的解決方案。我們不必一次性設(shè)計出整個系統(tǒng),但可以反復(fù)使用這些模式,然后看著一套可重用的對象作為結(jié)果出現(xiàn)。 總結(jié) 我在本文中簡要分析了構(gòu)建Session Facade 的一些規(guī)則。您已經(jīng)看到了該如何組織Session Facade 所調(diào)用的對象,如何著手設(shè)計Session Facade。您還看到了設(shè)計能與Session facade 配合得很好的用例控制器的一些方法。我希望,這些規(guī)則的應(yīng)用能提高您的 EJB 設(shè)計的適應(yīng)性和性能。 致謝 感謝 Martin Fowler 審讀了本文的草稿并提出了深刻的意見。同時感謝 Craig Larman 的深刻見解,他使我明白事實上Session facade 有兩種互補模式。 參考書目 Erich Gamma、Richard Helms、Ralph Johnson 與 John Vlissides 合著的 Design Patterns: Elements of Reusable Object-Oriented Design,Addison-Wesley,1995。 Gamma Martin Fowler 的 Analysis Patterns: Reusable Object Oriented Model,Addison-Wesley,1997。 Fowler Martin Fowler 的 Information Systems Architectur。[Fowler 2001] Sherman Alpert、Kyle Brown 與 Bobby Woolf 合著的 The Design Patterns Smalltalk Companio,Addison-Wesley,1996。 Alpert William Brown、Ralph Malveau、Hays McCormick 與 Thomas Mobray 合著的 AntiPatterns: Refactoring Software, Architectures, and Projects in Crisis,John Wiley and Sons,1998。[Brown 1998] Kyle Brown、Philip Eskelin 與 Nat Pryce 合著的 “A small pattern language for Distributed Component Design,是提交給 1999 年在 Illinois 的 Monticello 召開的程序模式語言(the Pattern Language of Programs,PloP)大會的論文,在 Ratio Group Web site 有它的完整鏡像發(fā)布。[Brown 1999] Kyle Brown 的 “Layered Architectures for EJB System,VisualAge Developer Domain。[Brown 2000] Kyle Brown 的 “Choosing the right EJB type:Some Design Criteria,VisualAge Developer Domain。[Brown 2000a] Kyle Brown 與 et. al. 合著的 Enterprise Java Programming for IBM WebSphere,Addison-Wesley Longman,Boston,2001 年 5 月。[Brown 2001] “Session Facade, Sun Java 核心 J2EE 模式,Java 開發(fā)者連接。[Sun 2001] Harvey Gunther 的 “WebSphere Application Server Development Best Practices for Performance and Scalability。 Gunther “Session Enity Facade,Sun J2EE 規(guī)劃藍圖。[Sun 2000] Sun Microsystems,“EJB 2.0 規(guī)范,發(fā)布草案 2。[EJB 2.0] Richard Monson-Haefel,Enterprise JavaBeans,第二版,O´Reilly,2000。[Monson-Haefel] Ivar Jacobson 與 et.al 合著的 “The Unified SoftWare Development Process,Addison-Wesley,1999。[Jacobson 1999] 腳注 1 Erich Gamma、Richard Helms、Ralph Johnson 與 John Vlissides 合著的 Design Patterns: Elements of Reusable Object-Oriented Design,Addison-Wesley,1995,第 185 頁。 2 Erich Gamma、Richard Helms、Ralph Johnson 與 John Vlissides 合著的 Design Patterns: Elements of Reusable Object-Oriented Design,Addison-Wesley,1995,第 186 頁。 3Erich Gamma、Richard Helms、Ralph Johnson 與 John Vlissides 合著的 Design Patterns: Elements of Reusable Object-Oriented Design,Addison-Wesley,1995,第 187 頁。 4Erich Gamma、Richard Helms、Ralph Johnson 與 John Vlissides 合著的 Design Patterns: Elements of Reusable Object-Oriented Design,Addison-Wesley,1995,第 193 頁。 5William Brown、Ralph Malveau、Hays McCormick 與 Thomas Mobray 合著的 AntiPatterns: Refactoring Software, Architectures, and Projects in Crisis,John Wiley and Sons,1998,第 73 頁。 關(guān)于作者 Kyle Brown 是 IBM WebSphere Service 的高級 Java 顧問。Kyle 在 WebSphere Service 中的職責是就關(guān)于面向?qū)ο蟮闹黝}和Java 2 企業(yè)版(J2EE)技術(shù),向“財富 500 強客戶提供咨詢服務(wù)、教育以及指導(dǎo) 。他是 The Design Patterns Smalltalk Companion(設(shè)計模式 Smalltalk 伴侶)的合著者,也是一位著名的撰稿人,還是關(guān)于 Enterprise Java,OO 設(shè)計和設(shè)計模式主題的討論會的發(fā)言人。可通過 [email protected] 與 Kyle 聯(lián)系。 Java, java, J2SE, j2se, J2EE, j2ee, J2ME, j2me, ejb, ejb3, JBOSS, jboss, spring, hibernate, jdo, struts, webwork, ajax, AJAX, mysql, MySQL, Oracle, Weblogic, Websphere, scjp, scjd
上一條:不要重新分配被鎖定對象的對象引用下一條:詳解Jackson的基本用法
相關(guān)文章:
1. IntelliJ IDEA設(shè)置默認瀏覽器的方法2. idea設(shè)置提示不區(qū)分大小寫的方法3. HTTP協(xié)議常用的請求頭和響應(yīng)頭響應(yīng)詳解說明(學習)4. IntelliJ IDEA創(chuàng)建web項目的方法5. VMware中如何安裝Ubuntu6. docker容器調(diào)用yum報錯的解決辦法7. .NET SkiaSharp 生成二維碼驗證碼及指定區(qū)域截取方法實現(xiàn)8. CentOS郵件服務(wù)器搭建系列—— POP / IMAP 服務(wù)器的構(gòu)建( Dovecot )9. css代碼優(yōu)化的12個技巧10. django創(chuàng)建css文件夾的具體方法
排行榜
