跳轉到內容

JavaBeans

75% developed
來自華夏公益教科書

導航使用者介面主題:v  d  e )


任何現代計算機語言的框架都以可重用性為核心。在重複的環境中使用之前構建的元件通常是可取的。在快速應用程式開發中,這些元件被證明更有用,因為您可以將它們從元件列表中拖出並在專案中的其他地方使用它們。藉助 JavaBeans 架構,這種級別的可重用性被新增到 Java 程式語言中。

JavaBeans 是主流的 Java 元件模型,由 Sun Microsystems 於 1996 年推出。JavaBeans 的定義如下

"JavaBean 是一個可重用的軟體元件,可以在構建工具中以可視方式操作。"

與元件模型一起,Sun 釋出了一個簡單的視覺化組合工具 BeanBox。它主要用於實驗 Bean,而不是提供專業的 IDE。對於現實世界的應用程式,最好部署在支援 JavaBeans 視覺化組合的 Java IDE 上,例如 Visual Age 或 JBuilder。

正如我們將看到的,JavaBeans 本質上與標準 Java 類沒有什麼區別,這使得元件模型非常易於使用。使 JavaBean 與普通 Java 類不同的原因是,JavaBean 遵循Oracle JavaBeans 標準(術語JavaBean或簡稱bean也指 JavaBean 類的例項)。有一套為促進重用而採用的功能和約定

  • 存在無引數建構函式;
  • 支援永續性;
  • 透過 getter 和 setter 方法操作的屬性;
  • 支援內省;
  • 事件作為 Bean 之間通訊的機制;
  • 透過屬性編輯器支援自定義。

JavaBeans 標準提供了一個框架,用於建立供 GUI 工具(包括 Java 開發環境)使用的物件。但在更常見的用法中,bean 是一個可序列化的類,它遵循其屬性的 JavaBeans 命名約定。這些命名標準使使用 Java 內省 變得容易。

為了遵循這些標準,bean 需要一個或多個屬性抽象,它們表示物件的不同狀態值。屬性具有名稱(有效的 Java 識別符號)和型別(引用型別基本型別陣列型別)。預設情況下,JavaBean 類的屬性是透過存在 getter 方法、setter 方法或兩者來推斷的。

  • 用於從 bean 獲取屬性值的 getter 方法。名稱通常為 getPropertyName 格式。例如,String 屬性 whiskey 的 getter 方法是 public String getWhiskey()。對於布林屬性(其型別為 boolean),約定使用 isPropertyName 命名模式。

isDiscounted() 將是名為 discounted 的布林屬性的 getter 方法。因此,大多數 getter 方法的簽名是 public PropertyType getPropertyName()public boolean isPropertyName()

  • 用於為 bean 的屬性賦值的 setter 方法。setter 方法是 public void setPropertyName(PropertyType value) 格式的方法。對於前面的示例,setter 可以被呼叫為 setWhiskey("bourbon");

根據 JavaBeans 標準,按上述方式定義的 getter 和 setter 會自動確定類的屬性。但是,透過建立 java.beans.PropertyDescriptor 類,您可以透過顯式宣告屬性名稱以及每個屬性的 getter 和/或 setter 方法來指定備用實現。

屬性通常使用 私有 例項變數 來實現,但這並不是必需的。

一個簡單的 JavaBean

[編輯 | 編輯原始碼]

這是一個具有 int ageString color 屬性的簡單 JavaBean 型別的示例。

Computer code 程式碼清單 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;
  }
}

永續性

[編輯 | 編輯原始碼]

物件成為 bean 的要求是定義一個公共無引數建構函式,以便構建工具可以以一種簡單的方式例項化 bean(在 Point bean 中,隱式給出無引數建構函式)。其次,需要實現 java.io.Serializablejava.io.Externalizable 介面之一。這些介面沒有規定任何方法的實現,但它們是一種認可,表明該 bean 可以儲存在永續性儲存中,例如在檔案或資料庫中。這樣,bean 可以在應用程式關閉或跨網路傳輸後恢復。在永續性儲存中儲存元件狀態的能力稱為永續性。Java 提供了一個標準的序列化機制,這使得序列化物件變得非常容易。或者,可以透過實現 Externalizable 介面以自定義方式儲存元件(例如以 xml 格式)。

bean 的屬性是所有可以透過公共方法訪問和修改的私有欄位。這些 getter 和 setter 方法應該透過遵循簡單的命名約定來標記:對於某個名為 xxx 的屬性,應該有一個 getXxx() 來返回屬性值,以及一個 setXxx() 來設定屬性。

在 Java 和 J2EE 程式設計中,您只能在將物件強制轉換為宣告它的類或介面時呼叫物件上的方法。bean 屬性的結構化定義對於比較幾個不應透過繼承相關的物件的單個通用屬性非常有用。

例如,程式可能同時包含一個代表公司員工的 bean,以及另一個包含公司佔用的建築物列表的 bean。編寫名為 listAssetNames() 的函式的程式設計師想要編寫一種簡單的方法來從幾個可以從 Employee 和 Building bean 獲取欄位的 bean 中獲取“name”欄位,並且該方法可以輕鬆地適應從其他可能尚未編寫的 bean 型別中獲取相同的欄位。

雖然可以透過重寫 Employee 和 Building 使它們都繼承自名為 NamedObject 的一個類,或者透過建立一個 NamedObject 介面來實現,但這兩種方法都有自己的問題。使用繼承會有限制,因為每個子類只能繼承自一個父類,這限制了可以共享屬性的不同類的數量,以及可以共享的通用屬性的數量。此外,使用繼承來表達除簡單的“is-a”關係之外的關係可能會令人困惑,檢視數十個類定義以查詢單個“啞”getter 函式的實現也會令人困惑。建立介面解決了多繼承規則導致的問題,因為類可以使用任意數量的介面,但它仍然要求明確地寫出每個共享屬性。

處理這種關係的最簡單、最優雅的方式是使用內省來讀取 bean 屬性。jakarta BeanUtils 包是處理需要以這種方式相關聯的物件的常用方法,因為它利用了 JavaBean 命名約定的規律性。

Computer code 程式碼清單 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;
}

Computer code 程式碼清單 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
}

JavaBeans 透過事件相互互動。事件是元件可以通知其他元件的通知,表明發生了某些有趣的事情。例如,事件可能是單擊按鈕或關閉視窗。bean 可以是事件的源和目標。要被通知有關事件的資訊,bean 必須在另一個 Bean 中註冊為偵聽器

Java 事件模型實現了觀察者設計模式,其效果是減少了元件間耦合。方法呼叫需要緊密耦合,因為呼叫者和接收者需要在編譯時彼此瞭解,而事件則完全透過介面進行所有通訊。

一種特殊的事件是 PropertyChangeEvents。它們用於限制某些屬性僅取特定值,例如對於月份,整數範圍為 1 到 12。每次修改這種繫結屬性時,都會向所有已註冊的 PropertyChangeListeners 傳送通知。

定製是透過屬性編輯器完成的。屬性編輯器是一個工具,用於在設計時定製特定屬性型別。屬性編輯器從所謂的屬性表啟用,屬性表顯示 bean 的所有屬性。如果選擇某個屬性進行定製,屬性表會找出屬性的型別,並顯示具有屬性當前值的適當屬性編輯器。

其他說明

[編輯 | 編輯原始碼]

JavaBean 元件模型的一大優勢在於它設計得很簡單。開發 JavaBeans 非常簡單,因為 Java 程式語言預設支援許多行為(例如平臺獨立性或打包機制)。但是,可以選擇為 bean 裝備額外的物件,例如BeanInfos 或自定義 PropertyEditors,以更靈活的方式使用元件模型。第二項功能是 Sun 根據 JavaBeans 元件模型設計了整個 Swing GUI 庫。因此,Swing 元件可以很容易地在視覺化構建工具中組合起來。

然而,JavaBeans並沒有實現元件模型的所有功能。一個缺點是JavaBeans被限制在Java程式語言中,而元件的重要目標是實現語言的獨立性。

[編輯 | 編輯原始碼]
  • Learning JavaTM, Niemeyer, P. 和 Knudsen, J.,第三版,2005,O'Reilly: Sebastopol, CA。第751-786頁


華夏公益教科書