事件機制是 JavaBeans 架構核心,實現元件間鬆耦合通訊。本文系統闡述事件狀態物件、事件監聽器介面、來源註冊/通知流程、適配器類別角色與標準設計模式。
繼承 java.util.EventObject,封裝事件發生時的上下文資訊。慣例類別名以 Event 結尾。
public class MouseMovedEvent extends EventObject {
private int x, y;
public MouseMovedEvent(Component source, Point loc) {
super(source); this.x = loc.x; this.y = loc.y;
}
public Point getLocation() { return new Point(x, y); }
}
繼承 java.util.EventListener (標記介面),定義回調方法。慣例介面名以 Listener 結尾。
public interface MouseMovedListener extends EventListener {
void mouseMoved(MouseMovedEvent e);
}
實作類別即為監聽器:
public class MyListener implements MouseMovedListener {
public void mouseMoved(MouseMovedEvent e) { /* 處理邏輯 */ }
}
來源類別維護監聽器清單,提供標準註冊/移除方法 (設計模式:add<ListenerType> / remove<ListenerType>)。
public abstract class EventSource {
private Vector listeners = new Vector<>();
public synchronized void addModelChangedListener(ModelChangedListener l) {
listeners.addElement(l);
}
public synchronized void removeModelChangedListener(ModelChangedListener l) {
listeners.removeElement(l);
}
protected void notifyModelChanged() {
// 1. 複製清單 (快照) 避免通知過程中清單變動
Vector snapshot;
synchronized(this) { snapshot = (Vector) listeners.clone(); }
// 2. 建立事件物件
EventObject e = new EventObject(this);
// 3. 逐一同步通知
for (ModelChangedListener l : snapshot) {
l.modelChanged(e);
}
}
}
關鍵點:synchronized 保護清單增刪與快照複製;快照模式避免 ConcurrentModificationException 且確保通知過程中新增/移除監聽器不影響本次廣播。
當監聽器介面包含多個方法、或來源與監聽器類型不匹配、或需附加條件過濾時,引入適配器類別作為中介。
// 範例:MouseAdapter 已實作 MouseListener/MouseMotionListener 所有方法為空
button.addMouseListener(new MouseAdapter() {
@Override public void mouseClicked(MouseEvent e) { doSomething(); }
});
EventObject 子類實例。