JavaBeans
| 導航 使用者介面 主題: |
任何現代計算機語言框架的核心都是可重用性。在重複的環境中使用以前構建的元件通常是可取的。在 快速應用程式開發 中,這些元件被證明更有用,因為您可以從元件列表中拖動它們並在專案中的其他地方使用它們。JavaBeans 架構透過 Java 程式語言添加了這種可重用性級別。
JavaBeans 是主流的 Java 元件模型,由 Sun Microsystems 於 1996 年推出。JavaBeans 定義如下
“JavaBean 是一個可重用的軟體元件,可以在構建工具中以可視方式進行操作。”
Sun 除了元件模型外,還發布了一個簡單的視覺化組合工具 BeanBox。它主要用於試驗 Bean,而不是提供專業 IDE。對於實際應用,最好部署在 Visual Age 或 JBuilder 等支援 JavaBeans 視覺化組合的 Java IDE 之一上。
正如我們將看到的,JavaBeans 本質上與標準 Java 類沒有區別,這使得元件模型非常易於使用。將 JavaBean 與普通 Java 類區分開來的原因是 JavaBean 遵循 Oracle JavaBeans 標準(術語“JavaBean”或簡稱“bean”也指 JavaBean 類的例項)。為了促進重用,採用了一組功能和約定
- 存在無引數建構函式;
- 支援永續性;
- 由 getter 和 setter 方法操作的屬性;
- 支援內省;
- 事件作為 Bean 之間通訊的機制;
- 支援透過屬性編輯器進行自定義。
JavaBeans 標準提供了一個框架,用於建立供 GUI 工具(包括 Java 開發環境)使用的物件。但在更常見的用法中,bean 是一個可序列化的類,它遵循其屬性的 JavaBeans 命名約定。這些命名標準使 Java 內省 易於使用。
為了遵循這些標準,Bean 需要一個或多個屬性抽象,它們代表物件的不同的狀態值。屬性具有名稱(有效的 Java 識別符號)和型別(引用型別、基本型別或陣列型別)。預設情況下,JavaBean 類屬性由存在 getter 方法、setter 方法或兩者推斷出來。
- getter 方法用於從 Bean 獲取屬性值。名稱通常為
getPropertyName格式。例如,String 屬性whiskey的 getter 方法為public String getWhiskey()。對於布林屬性(其型別為boolean),約定使用命名模式isPropertyName。
isDiscounted() 將是名為 discounted 的布林屬性的 getter 方法。因此,大多數 getter 方法的函式簽名為 public PropertyType getPropertyName() 或 public boolean isPropertyName()。
- setter 方法用於為 Bean 的屬性賦值。setter 方法為
public void setPropertyName(PropertyType value)格式的方法。對於前面的示例,setter 可以透過setWhiskey("bourbon");呼叫。
根據 JavaBeans 標準,按上述描述定義的 getter 和 setter 會自動確定類的屬性。但是,透過建立 java.beans.PropertyDescriptor 類,您可以透過顯式宣告屬性名稱以及每個屬性的 getter 和/或 setter 方法來指定備用實現。
屬性通常使用 private 例項變數實現,但這並非必需。
一個簡單的 JavaBean
[edit | edit source]這是一個具有屬性 int age 和 String color 的簡單 JavaBean 型別示例。
程式碼清單 9.12:Puppy.java
class Puppy implements java.io.Serializable {
private static final long serialVersionUID = 348652158488L;
private String color;
private int age;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
|
永續性
[edit | edit source]物件成為 Bean 的要求是定義一個公共無引數建構函式,以便構建工具可以以一種簡單的方式例項化 Bean(在 Point Bean 中,無引數建構函式是隱式給出的)。其次,需要實現 java.io.Serializable 或 java.io.Externalizable 介面之一。這些介面沒有規定任何方法的實現,但表示 Bean 可以儲存在持久儲存中,例如檔案中或資料庫中。這樣做可以使 Bean 在應用程式關閉或跨網路傳輸後恢復。在持久儲存中儲存元件狀態的能力稱為永續性。Java 提供標準序列化機制,使物件序列化非常容易。或者,可以透過實現 Externalizable 介面以自定義方式儲存元件(例如,以 xml 格式)。
屬性
[edit | edit source]Bean 的屬性是所有透過公共方法可訪問和可修改的私有欄位。這些 getter 和 setter 方法應透過遵循簡單的命名約定標記為這樣:對於某個名為 xxx 的屬性,應該有一個 getXxx() 返回屬性值,還有一個 setXxx() 設定屬性。
內省
[edit | edit source]在 Java 和 J2EE 程式設計中,只有將物件轉換為宣告該方法的類或介面時,才能呼叫物件上的方法。Bean 屬性的結構化定義對於比較幾個不應透過繼承關聯的物件的單個公共屬性非常有用。
例如,程式可以同時包含代表公司員工的 Bean 以及包含公司佔用的建築物列表的另一個 Bean。編寫名為 listAssetNames() 的函式的程式設計師想要編寫一種簡單的方法來從幾個 Bean 中獲取“name”欄位,這些 Bean 可以從 Employee 和 Building Bean 中獲取欄位,並且可以輕鬆地適應從其他型別可能尚未編寫好的 Bean 中獲取相同欄位。
雖然這可以透過重新編寫 Employee 和 Building 使得它們都繼承自名為 NamedObject 的一個類來實現,或者透過建立 NamedObject 介面來實現,但這兩種方法都有其自身的問題。使用繼承是有限的,因為每個子類只能從一個父類繼承,這限制了可以共享屬性的不同類的數量,以及可以共享的公共屬性的數量。此外,使用繼承來表達除簡單的“is-a”關係之外的關係可能會令人困惑,就像檢視數十個類定義來查詢某個“啞”getter 函式在何處實現一樣。建立介面修復了多重繼承規則引起的問題,因為一個類可以使用任意數量的介面,但它仍然要求顯式地拼出每個共享屬性。
處理這種關係最簡單、最優雅的方法是使用內省來讀取 Bean 屬性。Jakarta BeanUtils 包是處理需要以這種方式關聯的物件的常用方法,因為它利用了 JavaBean 命名約定的規律性。
程式碼清單 9.13:從 JavaBean 獲取屬性
public static Object getProperty(Object o, String propertyName) {
if (o == null ||
propertyName == null ||
propertyName.length() < 1) {
return null;
}
// Based on the property name build the getter method name
String methodName = "get" +
propertyName.substring(0,1).toUpperCase() +
propertyName.substring(1);
Object property = null;
try {
java.lang.Class c = o.getClass();
java.lang.reflect.Method m = c.getMethod(methodName, null);
property = m.invoke(o, null);
} catch (NoSuchMethodException e) {
// Handle exception
} catch (SecurityException e) {
// No permission; Handle exception
}
return property;
}
|
或
程式碼清單 9.14:使用 Apache Commons BeanUtils
import org.apache.commons.beanutils.PropertyUtils;
try {
Object myValue = PropertyUtils.getSimpleProperty(o, propertyName);
} catch (IllegalAccessException e) {
// Handle exception
} catch (InvocationTargetException e) {
// Handle exception
} catch (NoSuchMethodException e) {
// Handle exception
}
|
事件
[edit | edit source]JavaBeans 透過事件相互互動。事件是通知,一個元件可以告知其他元件,表示某些有趣的事情發生了。事件的示例可能是按鈕上的滑鼠點選或視窗關閉。Bean 可以是事件的源和目標。要了解事件,Bean 必須在另一個 Bean 中註冊為偵聽器。
Java 事件模型實現了觀察者設計模式,其效果是減少了元件間的耦合。方法呼叫需要緊密耦合,因為呼叫者和接收者需要在編譯時相互瞭解,而事件的所有通訊都僅透過介面進行。
一種特殊的事件是 PropertyChangeEvents。它們用於限制某些屬性只能取特定值,例如,對於月份,整數值在 1 到 12 之間。每次修改此類繫結屬性時,都會向所有已註冊的PropertyChangeListeners 傳送通知。
自定義
[edit | edit source]自定義透過屬性編輯器完成。屬性編輯器是一種用於在設計時自定義特定屬性型別的工具。屬性編輯器從所謂的屬性表中啟用,屬性表顯示 Bean 的所有屬性。如果選擇要自定義的屬性,屬性表將找出屬性的型別,並顯示包含屬性當前值的適當屬性編輯器。
其他說明
[edit | edit source]JavaBean 元件模型的一大優勢是它設計為簡單。開發 JavaBeans 非常簡單,因為許多行為(如平臺獨立性或打包機制)預設情況下在 Java 程式語言中得到支援。但是,可以可選地為 Bean 裝備額外的物件,如BeanInfos 或自定義PropertyEditors,以更靈活的方式使用元件模型。第二種方法是 Sun 根據 JavaBeans 元件模型設計了整個 Swing GUI 庫。因此,Swing 元件可以輕鬆地在視覺化構建工具中組合。
但是,JavaBeans 並沒有實現元件模型的所有功能。一個缺點是 JavaBeans 僅限於 Java 程式語言,而元件的重要目標是獨立於實現語言。
推薦讀物
[edit | edit source]- Learning JavaTM,Niemeyer,P. 和 Knudsen,J.,第三版,2005 年,O'Reilly:Sebastopol,CA。第 751-786 頁