一.javabean
一、 javabean 是什么?
Bean的中文含義是“豆子”,顧名思義,JavaBean是指一段特殊的Java類,
就是有默然構造方法,只有get,set的方法的java類的對象.
專業點解釋是:
JavaBean定義了一組規則
JavaBean就是遵循此規則的平常的Java對象
滿足這三個條件:
1.執行java.io.Serializable 接口
2.提供無參數的構造器
3.提供getter 和 setter方法訪問它的屬性.
簡單地說,JavaBean是用Java語言描述的軟件組件模型,其實際上是一個類。這些類遵循一個接口格式,以便於使函數命名、底層行為以及繼承或實現的行為,可以把類看作標准的JavaBean組件進行構造和應用。
JavaBean一般分為可視化組件和非可視化組件兩種。可視化組件可以是簡單的GUI元素,如按鈕或文本框,也可以是復雜的,如報表組件;非可視化組件沒有GUI表現形式,用於封裝業務邏輯、數據庫操作等。其最大的優點在於可以實現代碼的可重用性。JavaBean又同時具有以下特性。
易於維護、使用、編寫。
可實現代碼的重用性。
可移植性強,但僅限於Java工作平台。
便於傳輸,不限於本地還是網絡。
可以以其他部件的模式進行工作。
對於有過其他語言編程經驗的讀者,可以將其看作類似微軟的ActiveX的編程組件。但是區別在於JavaBean是跨平台的,而ActiveX組件則僅局限於Windows系統。總之,JavaBean比較適合於那些需要跨平台的、並具有可視化操作和定制特性的軟件組件。
JavaBean組件與EJB(Enterprise JavaBean,企業級JavaBean)組件完全不同。EJB 是J2EE的核心,是一個用來創建分布式應用、服務器端以及基於Java應用的功能強大的組件模型。JavaBean組件主要用於存儲狀態信息,而EJB組件可以存儲業務邏輯。
2 使用JavaBean的原因
程序中往往有重復使用的段落,JavaBean就是為了能夠重復使用而設計的程序段落,而且這些段落並不只服務於某一個程序,而且每個JavaBean都具有特定功能,當需要這個功能的時候就可以調用相應的JavaBean。從這個意義上來講,JavaBean大大簡化了程序的設計過程,也方便了其他程序的重復使用。
JavaBean傳統應用於可視化領域,如AWT(窗口工具集)下的應用。而現在,JavaBean更多地應用於非可視化領域,同時,JavaBean在服務器端的應用也表現出強大的優勢。非可視化的JavaBean可以很好地實現業務邏輯、控制邏輯和顯示頁面的分離,現在多用於后台處理,使得系統具有更好的健壯性和靈活性。JSP + JavaBean和JSP + JavaBean + Servlet成為當前開發Web應用的主流模式。
3 JavaBean的開發
在程序設計的過程中,JavaBean不是獨立的。為了能夠更好地封裝事務邏輯、數據庫操作而便於實現業務邏輯和前台程序的分離,操作的過程往往是先開發需要的JavaBean,再在適當的時候進行調用。但一個完整有效的JavaBean必然會包含一個屬性,伴隨若干個get/set(只讀/只寫)函數的變量來設計和運行的。JavaBean作為一個特殊的類,具有自己獨有的特性。應該注意以下3個方面。
JavaBean類必須有一個沒有參數的構造函數。
JavaBean類所有的屬性最好定義為私有的。
JavaBean類中定義函數setXxx() 和getXxx()來對屬性進行操作。其中Xxx是首字母大寫的私有變量名稱。
二.DTO
什么是DTO
在分布式系統中,客戶端和服務器端交互有兩種情形:第一個是客戶端從服務器端讀取數據;第二個是客戶端將本身的數據傳遞給服務器端。
當有客戶端要向服務器端傳輸大量數據的時候,可以通過一個包含要傳輸的所有數據的方法調用來完成。這在小數據量的時候缺點並不明顯,但是如果要傳遞包含有大量信息的數據的時候,這將變得難以忍受。下面的方法是任何人看了都會害怕的:
public void save(String id,String number,String name,int type,int height,
int width,BigDecimal weight,BigDecimal price,String description)
這種接口也是非常的脆弱,一旦需要添加或者刪除某個屬性,方法的簽名就要改變。
當客戶端要從服務器端取得大量數據的時候,可以使用多個細粒度的對服務器端的調用來獲取數據。比如:
ISomeInterface intf = RemoteService.getSomeInterface();
System.out.println("您要查詢的商品的資料為:");
System.out.println("編號:"+intf.getNumber(id));
System.out.println("姓名:"+intf.getName(id));
System.out.println("類型:"+intf.getType(id));
System.out.println("高度:"+intf.getHeight(id));
System.out.println("寬度:"+intf.getWidth(id));
System.out.println("價格:"+intf.getPrice(id));
System.out.println("描述信息:"+intf.getDescription(id));
這種方式中每一個get***方法都是一個對服務器 的遠程調用,都需要對參數和返回值進行序列化和反序列化,而且服務器進行這些調用的時候還需要進行事務、權限、日志的處理,這會造成性能的大幅下降。如果 沒有使用客戶端事務的話還會導致這些調用不在一個事務中從而導致數據錯誤。
系統需要一種在客戶端和服務器端之間高效、安全地進 行數據傳輸的技術。DTO(Data Transfer Object,數據傳送對象)是解決這個問題的比較好的方式。DTO是一個普通的Java類,它封裝了要傳送的批量的數據。當客戶端需要讀取服務器端的數 據的時候,服務器端將數據封裝在DTO中,這樣客戶端就可以在一個網絡調用中獲得它需要的所有數據。
還是上面的例子,服務器端的服務將創建一個DTO並封裝客戶端所需要的屬性,然后返回給客戶端:
ISomeInterface intf = RemoteService.getSomeInterface();
SomeDTOInfo info = intf.getSomeData(id);
System.out.println("您要查詢的商品的資料為:");
System.out.println("編號:"+info.getNumber());
System.out.println("姓名:"+info.getName());
System.out.println("類型:"+info.getType());
System.out.println("高度:"+info.getHeight());
System.out.println("寬度:"+info.getWidth());
System.out.println("價格:"+info.getPrice());
System.out.println("描述信息:"+info.getDescription());
使用DTO 的時候,一個主要問題是選擇什么樣的DTO:這個DTO能夠容納哪些數據,DTO的結構是什么,這個DTO是如何產生的。DTO是服務器端和客戶端進行通 信的一個協議格式,合理的DTO設計將會使得服務器和客戶端的通信更加順暢。在水平開發模式(即每個開發人員負責系統的不同層,A專門負責Web表現層的 開發,B專門負責服務層的開發)中,在項目初期合理的DTO設計會減少各層開發人員之間的糾紛;在垂直開發模式(即每個開發人員負責不同模塊的所有層,A 專門負責庫存管理模塊的開發,B專門負責固定資產模塊的開發)中,雖然開發人員可以自由地調整DTO的結構,但是合理的DTO設計仍然會減少返工的可能 性。
實現DTO 最簡單的方法是將服務端的域對象(比如Hibernate中的PO、EJB中的實體Bean)進行拷貝然后作為DTO傳遞。采用域對象做DTO比較簡單和 清晰,因為DTO與域模型一致,所以了解一個結構就夠了。這樣做也免去了DTO的設計,使得開發工作變得更快。這種做法的缺點是域DTO的粒度太大以至於 難以滿足客戶端的細粒度的要求,客戶端可能不需要訪問那些域中的所有屬性,也可能需要不是簡單地被封裝在域中的數據,當域DTO不能滿足要求的時候就需要 更加細粒度的DTO方案。目前主流的DTO解決方案有定制DTO、數據傳送哈希表、數據傳送行集。
10.2 域DTO
域模型是指從業務模型中抽取出來的對象模型,比如商品、倉庫。在J2EE中,最常見的域模型就是可持久化對象,比如Hibernate中的PO、EJB中的實體Bean。
在分布式系統中,域模型完全位於服務器端。根據持久 化對象可否直接傳遞到客戶端,域對象可以分為兩種類型:一種是服務器端的持久化對象不可以直接傳遞到客戶端,比如EJB中的實體Bean是不能被傳遞到客 戶端的;一種是持久化對象可以直接傳遞到客戶端,比如Hibernate中的PO變為detached object以后就可以傳遞到客戶端。
EJB中的實體Bean不能直接傳遞到客戶端,而且實體Bean不是一個簡單的JavaBean,所以也不能通過深度克隆(deep clone)創造一個新的可傳遞Bean的方式產生DTO。針對這種情況,必須編寫一個簡單的JavaBean來作為DTO。
下面是一個系統用戶的實體Bean的代碼:
1 abstract public class SystemUserBean implements EntityBean 2 { 3 EntityContext entityContext; 4 public java.lang.String ejbCreate(java.lang.String userId) 5 throws CreateException 6 { 7 setUserId(userId); 8 return null; 9 } 10 public void ejbPostCreate(java.lang.String userId) 11 throws CreateException 12 { 13 } 14 public void ejbRemove() throws RemoveException 15 { 16 } 17 public abstract void setUserId(java.lang.String userId); 18 public abstract void setName(java.lang.String name); 19 public abstract void setPassword(java.lang.String password); 20 public abstract void setRole(java.lang.Integer role); 21 public abstract java.lang.String getUserId(); 22 public abstract java.lang.String getName(); 23 public abstract java.lang.String getPassword(); 24 public abstract java.lang.Integer getRole(); 25 public void ejbLoad() 26 { 27 } 28 public void ejbStore() 29 { 30 } 31 public void ejbActivate() 32 { 33 } 34 public void ejbPassivate() 35 { 36 } 37 public void unsetEntityContext() 38 { 39 this.entityContext = null; 40 } 41 public void setEntityContext(EntityContext entityContext) 42 { 43 this.entityContext = entityContext; 44 } 45 }
DTO生成器
將PO經過一定形式的轉換,傳遞給客戶端,使得客戶端能夠方便地使用傳過來的DTO,這就是DTO生成器要解決的問題。把問題具體分解,我們發現DTO生成器的功能如下:
l 允許客戶端指定加載哪些屬性,這樣DTO生成器就只加載客戶端指定的屬性,其他屬性不予以加載,這減小了網絡流量。
l 屏蔽CGLib、Hibernate等的影響,客戶端可以把DTO當成一個沒有任何副作用的普通JavaBean使用。
l 允許客戶端將修改后的DTO傳遞回服務器端進行更新。
采用簡單的對象克隆方法無法得到滿足要求的DTO, 因為克隆以后的對象仍然是和PO一樣的被代理對象。更好的解決方法就是重新生成一個與PO的原有類型(比如PersonInfo,而非 PersonInfo$CGLib$Proxy)一致的JavaBean作為DTO,然后將客戶端需要的PO中的屬性賦值到DTO中。在復制過程中,因為 PO以及關聯的對象的信息已經被LazyLoad破壞得亂七八糟了,所以我們必須要通過一種機制知道對象的字段有哪些、字段的類型是什么、字段是否是關聯 對象、關聯的類型是什么。了解這些信息的最好方式就是通過元數據,案例系統的元數據機制就可以滿足這個要求,而且Hibernate也有元數據機制能提供 類似的信息
三.VO
一、PO:persistant object 持久對象,可以看成是與數據庫中的表相映射的java對象。使用Hibernate來生成PO是不錯的選擇。
二、VO:value object值對象。通常用於業務層之間的數據傳遞,和PO一樣也是僅僅包含數據而已。但應是抽象出的業務對象,可以和表對應,也可以不,這根據業務的需要.
有一種觀點就是:PO只能用在數據層,VO用在商業邏輯層和表示層。各層操作屬於該層自己的數據對象,這樣就可以降低各層之間的耦合,便於以后系統的維護和擴展。如果將PO用在各個層中就相當於我們使用全局變量,我們知道在OO設計非常不贊成使用全局變量。
但是每次都得進行VO-PO的轉換,也確實很煩。我覺得有時候也可以在某個商業邏輯或者表示層使用PO,此時在這個商業邏輯的過程中PO的狀態是不發生變化的,比如顯示一條商品詳細信息的商業邏輯。
在開發過的項目中,規模都很小,我一直都把PO當VO用,因為PO確實很方便,結合Hibernate的DAO,我使用JAVA的集合對象作為值傳遞的載體,當然Struts也是我的不二之選。