程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 在J2EE中實現Observer模式

在J2EE中實現Observer模式

編輯:關於JAVA

引言:

設計模式是經驗的文檔化。它是對被用來在特定場景下解決一般設計問題的類和相互通信 的對象的描述。更通俗的來說,它是一個問題/解決方案對。一旦我們掌握了設計模式,就等 於擁有了一支強有力的專家隊伍。它甚至能夠使面向對象的新手利用前人的經驗找出職責明 確的類和對象,從而獲得優雅的解決方案。由於設計模式也是重構的目標,如果在設計的初 期適當地引入設計模式,可以減少重構的工作量。

但是,我們也不能陷入模式的陷阱,為了使用模式而去套模式,那樣會陷入形式主義。我 們在使用模式的時候,一定要注意模式的意圖(intent),而不要過多的去關注模式的實現 細節,因為這些實現細節在特定情況下,可能會發生一些改變。不要頑固地認為設計模式一 書中的類圖或實現代碼就代表了模式本身。

下面,我們來討論一下為什麼要在分布式、多層系統中使用Observer模式。

多層體系結構(multi-tier architecture):

三層體系結構是多層體系結構中最簡單的一種,它一般包括:

表示層(presentation)-窗口、報表-

業務邏輯層(business logic)-管理業務過程的任務和規則。它又可以細分為領域對象層 (代表領域概念)和服務層(提供數據庫交互、安全性、打印報表)。

存儲層(storage)-持久化存儲機制。如數據庫服務器等。

圖一:三層體系結構

而Java 2平台企業版(J2EE)是一種利用Java 2平台來簡化諸多與多級企業解決方案的開 發、部署和管理相關的復雜問題的體系結構。它是開放的、基於標准的平台,用以開發、部 署和管理N層結構、面向Web的,以服務器為中心的企業級應用。

為了支持領域對象的復用,並且使領域對象的接口變更所帶來的影響最小化。我們將領域 層(模型)和表示層(視圖)相分離。

采用模型-視圖模式的意義在於:

支持聚合度更高的模型定義,使模型的定義可以集中在領域過程的定義,而不是圖形界面 上。

允許將模型和用戶界面並行開發。

使用戶界面的需求變化對領域層所造成的影響最小化。

允許建立與一個現有的領域層對象相連接的新視圖,同時不影響領域層。

允許一個模型同時有多個視圖,例如使用SVG和表格。

允許模型層獨立於用戶界面層執行。

而這恰恰與Observer模式的意圖相吻合。因此我們有必要跨層來實現Observer模式。

其實,在應用中更多的是采用MVC框架來架構整個企業應用的。在MVC框架中,Model和 View之間存在著依賴關系,是Observer模式的典型應用。當然MVC框架還包括其它模式如 Composite模式和Strategy模式。在J2EE平台中,我們可以把Web Tier(包括Jsp和servelet 和JavaBean)看作是表示層,EJB Tier看作是領域層。而controller可能跨距Web Tier和 EJB Tier。

在Java類庫中采用Java.util.Observable類和Java.util.Observer接口來實現Observer模 式,它們在單個的Java VM.中運行的很好,但如果想在EJB中使用它們就會有一些問題。這正 如我們引言中提到的,模式的具體實現在特定情況下,可能會發生一些改變。

值傳遞還是遠程引用傳遞?

值傳遞:

在Java RMI中要求所有的參數和返回類型是JAVA的基本類型或實現Java.io.Serilizable 的對象。串行化對象通過值傳遞(又名拷貝傳遞),而不是引用傳遞,這意味著在某一層中 串行化對象的更並不自動影響到其它的對象。

遠程引用傳遞:

對於EJB對象而言,它由兩個接口(home接口和remote接口)和一 個類組成。容器會根據ejb規范來生成實現上面兩個接口的類(我們分別稱為xxxEJBHome對象 和xxxEjbObject對象)。在較多的容器的實現方案中,xxxEJBHome對象使用了factory模式來 創建xxxEjbObject對象;xxxEjbObject對象則采用proxy模式,作為xxxBean的代理類。在生 成以上兩個對象的同時,容器會從部署文件中讀取關於安全、事務、持久性等服務並在 xxxEjbObject對象和xxxEJBHome對象中添加以上服務的代碼。而且xxxEJBHome對象和 xxxEjbObject對象都是分布式對象,我們在此只討論xxxEjbObject對象。所謂分布式對象, 從本質上來講,分為3個部分:object server、skeleton、stub。其中object server和 skeleton位於服務器端,而stub位於客戶端。Object server負責實現業務邏輯,skeleton負 責marshal和unmarshal方法簽名。

圖二:分布式對象

顯然,EJB的客戶(調用EJB的對象)可以是任何對象,包括EJB和一般的Java類甚至是用任何 語言寫的corba客戶端。

從EJB的客戶視角來看的話,我們只能看到一個home接口、一 個remote接口(對於實體bean的話,還可以看見一個主鍵類,而bean類對客戶是不可見的) 。但我們從上面的論述,我們可以知道,對於remote接口中地方法調用,實際上是多態地調 用XXX_Stub類。即XXX_Stub對象對客戶具有可見性(但這種可見性是透明的,即客戶不知道 這種可見性的存在)。由於,XXX_Stub對象和Object Server實現了相同的接口,並且Object server真正實現了業務邏輯。所以,當在客戶端調用XXX_Stub對象的方法時候,XXX_Stub對 象通過socket通信機制將方法簽名傳給XXX_Skeleton對象,XXX_Skeleton對象在去委托 Object Server完成業務處理邏輯。因此,Object Server本身發生了改變。我們稱XXX_Stub 對象是Object Server對象的遠程引用,並認為當分布式對象作為參數傳遞的時候,是通過引 用傳遞的(會產生副作用�D�D即改變參數對象),只不過這種引用是遠程引 用。可以參見本文的示范代碼,了解遠程引用。

在J2EE中實現Observer模式的典型錯誤

為了說明問題,我們從一個簡單例子開始著手:假設一個或多個位於web tier層的、可以 序列化(serilizable)的Java類,想要從位於EJB tier層的一個或多個實體bean中獲取數據( 它們可能是分布在不同EJB SERVER中)。可以把web tier層的Java類看成是一個分布式異構 數據源的聯合視圖。顯然,它們之間存在著依賴關系,而且這兩個方面要相互獨立(位於不 同的tier),並且當一個對象改變的同時,不知道具體又多少個對象有待改變。因此,我們 決定用OBSERVER模式來實現這個問題。把bean作為observer,把Entity Bean作為Subject。 參照圖三Observer設計模式

圖三:Observer設計模式

這樣,就會使起observer作用的Java類對起subject作用的entity bean中具有參數可見性 ,而且由於它們可以位於不同的機器上,所有我們要為Java類實現serilizable接口,從而使 它可以在網絡上傳遞。看上去似乎非常完美,但不幸的是:在運行的時候,我們發現客戶端 並不能自動更新。究其原因,我們發現,原來Java類是通過值傳遞的,即entity bean中有一 個Java類的拷貝,它對拷貝進行修改,但不會影響原來的Java類。

但如果我們在另外一種情況下,把entity bean作為observer,而使Java類作為subject, 由於Java類擁有entity bean的遠程引用,當subject產生事件的時候,會通知entity bean的 遠程引用作相應的改動。此時與Java類位於不同tier的entity bean的發生了真正的改動,從 而實現了事件通知范型的observer模式。另外,為了使observer可以觀察多個subject, entity bean要擁有observer對象,而這些observer對象(Java類)通過值傳遞被序列化到 entity bean中,而且這種序列化是深度序列化。由於observer只是准備從subject中提取數 據,而不是改變subject的數據,所有這時候的值傳遞是可行的。但是,由於EJB規范的要求 ,所有商務方法都要拋出java.rmi.RemoteException,所以單純的從java類庫提供的Observer 接口繼承是不行的。具體的細節可以參見ejb observer pattern文檔(參考 EJBObserverPattern)。

注意:文檔中的附帶程序在JB5.0+BAS4.5中會出現corba marshal的問題,如果你只是為 了實現一個subject對應多個observer,而且是subject將所有的數據推給observer的話,可 以將EJBObserver接口中的update(EJBObservable observable,Object args)改為update (EJBObservable observable,Object args),這樣可以使程序在JB5.0+BAS4.5集成運行環 境中通過。

使用JMS在J2EE中實現Observer模式

消息系統允許分開的未耦合的應用程序之間可靠地異步通信。它使消息產生者和使用者之 間的關系是一種"松耦合"的關系。對於使用者,它不在乎誰產生了消息,產生者是否仍在網 絡上以及消息是什麼時候產生的。這就允許建立動態的,可靠的和靈活的系統。整個的子系 統能被修改而不會影響系統的其他部分。其實,領域層和表示層的分離的目的也就在於此。

在消息系統中,通常有兩種消息類型:1)發布/訂閱(publish/subscribe)。發布/訂閱 消息系統支持一個事件驅動模型,消息產生者和使用者都參與消息的傳遞。產生者發布事件 ,而使用者訂閱感興趣的事件,並使用事件。產生者將消息和一個特定的主題(Topic)連在一 起,消息系統根據使用者注冊的興趣,將消息傳給使用者。2)點對點(Peer to peer)。在 點對點的消息系統中,消息分發給一個單獨的使用者。它維持一個"進入"消息隊列。消息應 用程序發送消息到一個特定的隊列,而客戶端從一個隊列中得到消息。

在消息系統中,我們可以通過JMS和消息驅動Bean(Message-Driven Bean),用來實現應 用程序各個部件之間的異步消息傳遞。對於Observer模式而言,我們會優先地選用發布/訂閱 (publish/subscribe)模型。在編寫事件的生產者和事件的消費者代碼的時候,我們可以直 接使用JMS API來編寫Producer和Consumer,但是如果事件的消費者位於EJB Tier時,最好采 用消息驅動Bean(Message- Driven Bean)。因為消息驅動Bean通常配置成是一個特別的主 題(topic)或隊列的客戶端,作為消息的使用者。它大大地簡化了創建一個JMS使用者,創 建和配置一個JMS消息使用者這些功能都交由EJB容器來做了。開發人員只需簡單地實現消息 驅動Bean的接口,配置給EJB服務器,用來創建一個接收消息的商業邏輯部件。另外,當事件 的消費者同時有多個,我們可以使用MDB Facade模式來實現Observer模式。

圖四:MDB facade模式

MDB Facade模式實際上是Session Bean Facade模式的一個變種,因為MDB從本質上來說非 常類似於一個無狀態的Session Bean,只不過MDB沒有remote接口和home接口。圖四的MDB Facade模式也可以和Session Bean Facade模式結合起來使用,即一個MDB作為多個Session Bean的Facade,一個Session Bean作為多個Entity Bean的Facade。從而實現消息的傳遞。

代碼細節可以參照本文的示范代碼,它在BEA weblogic中運行通過。

總結

我們使用模式的時候,一定要注意模式的意圖(intent),而不要過多的去關注模式的實 現細節,因為這些實現細節在特定情況下,可能會發生一些改變。在Java類庫中采用 Java.util.Observable類和Java.util.Observer接口來實現Observer模式,它們在單個的 Java VM.中運行的很好,但如果想在EJB中使用它們就會有一些問題。本文主要討論了在分布 式、多層的J2EE平台中如何通過EJB Observer Pattern和JMS來實現Observer模式。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved