JavaBeans 規範定義了元件化開發的標準契約,其中 Constrained Properties(受限屬性) 與 Event Model(事件模型) 是實現元件間鬆耦合通訊、支援視覺化建構工具的關鍵機制。本文深入解析這兩大核心特性的設計原理、實作模式與最佳實務。
受限屬性允許其他物件(Vetoable Change Listeners)在屬性值變更前進行攔截與否決。若任一監聽器拋出 PropertyVetoException,屬性變更將被取消,原值保持不變。
java.beans.VetoableChangeSupport:管理否決監聽器清單、觸發否決事件java.beans.VetoableChangeListener:監聽器介面,單一方法 vetoableChange(PropertyChangeEvent evt)java.beans.PropertyVetoException:否決時拋出的受檢例外public class JellyBeans extends Canvas {
private VetoableChangeSupport vetos = new VetoableChangeSupport(this);
private PropertyChangeSupport changes = new PropertyChangeSupport(this);
private int priceInCents;
public void setPriceInCents(int newPrice) throws PropertyVetoException {
int oldPrice = this.priceInCents;
// 1. 觸發否決事件,監聽器可拋出 PropertyVetoException
vetos.fireVetoableChange("priceInCents", oldPrice, newPrice);
// 2. 無否決則更新值
this.priceInCents = newPrice;
// 3. 觸發一般屬性變更事件
changes.firePropertyChange("priceInCents", oldPrice, newPrice);
}
// 註冊/移除否決監聽器
public void addVetoableChangeListener(VetoableChangeListener l) {
vetos.addVetoableChangeListener(l);
}
public void removeVetoableChangeListener(VetoableChangeListener l) {
vetos.removeVetoableChangeListener(l);
}
// 同理需提供 PropertyChangeListener 註冊方法...
}
fireVetoableChange,再更新值,最後 firePropertyChangethrows PropertyVetoException事件模型是 JavaBeans 元件互動的基石,定義了「事件源」→「事件物件」→「事件監聽器」的標準協作流程。
| 要素 | 命名慣例 | 基底類別/介面 | 說明 |
|---|---|---|---|
| 事件狀態物件 | *Event | java.util.EventObject | 封裝事件相關狀態(如座標、按鍵碼) |
| 事件監聽器介面 | *Listener | java.util.EventListener | 定義處理方法簽章(如 mouseMoved(MouseEvent e)) |
| 事件源 | 無固定慣例 | 無 | 提供 add/remove<ListenerType>Listener 註冊方法 |
public class EventSource {
private final List<MyListener> listeners = new ArrayList<>();
public synchronized void addMyListener(MyListener l) {
listeners.add(l);
}
public synchronized void removeMyListener(MyListener l) {
listeners.remove(l);
}
protected void fireMyEvent(MyEvent event) {
// 複製清單避免並發修改
List<MyListener> snapshot;
synchronized (this) { snapshot = new ArrayList<>(listeners); }
for (MyListener l : snapshot) {
l.myEventOccurred(event);
}
}
}
當監聽器介面包含多個方法,但開發者僅關心其中幾個時,可使用適配器類別(Adapter)提供空實作,減少樣板碼。現代 IDE 多自動產生匿名內部類或 Lambda 表達式,適配器類較少手寫。
Constrained Properties 與 Event Model 構成了 JavaBeans 互動與整合的骨幹。雖然現代框架(Spring、JavaFX、Android)已將這些概念內建或重新設計,但理解其底層契約對於除錯、遷移舊系統、設計自訂元件框架仍具核心價值。