觀察者模式定義了一種一對多的依賴關係:當一個主題對象的狀態發生變化時,所有依賴它的觀察者都會收到通知並自動更新。這實現了主題與觀察者之間的鬆散耦合。
update()。Java 在 java.util 包下提供了 Observable 類與 Observer 介面,可直接用於快速構建觀察者機制。
setChanged()Observable 內部有一個 changed 標誌(預設 false)。notifyObservers() 會先檢查此標誌,唯有 true 時才會分發通知。因此流程必須是:
setChanged()notifyObservers(args)// 1. 被觀察者:繼承 Observable
public class MyButton extends Observable {
public void addListeners(Observer o) { addObserver(o); }
public void process(Object args) {
setChanged(); // 關鍵步驟
notifyObservers(args); // 分發通知
}
}
// 2. 觀察者:實現 Observer 介面
public class ClickObserver implements Observer {
public void update(Observable o, Object arg) {
System.out.println("click: " + arg);
}
}
// 3. 測試驅動
MyButton btn = new MyButton();
btn.addObserver(new ClickObserver());
btn.process("huhx"); // 輸出: click: huhx
Vector 儲存觀察者(線程安全)。addObserver() 同步加入向量。notifyObservers() 同步複製觀察者陣列,清除 changed 標誌,然後反向遍歷呼叫 update()。內建 API 無法針對特定事件類型通知特定觀察者。自定義框架可解決此問題。
CLICK、PRESS、ALL 等事件類型。Observer,方法簽名為 actionPerformed(MyObservable, Object)。ClickListener、PressListener 等。notifyFixObserver 中進行 instanceof 判斷並精準分發。private void notifyFixObserver(int event, Object args) {
for (int i = arrLocal.length - 1; i >= 0; i--) {
Listener listener = (Listener) arrLocal[i];
switch (event) {
case Event.CLICK:
if (listener instanceof ClickListener)
((ClickListener)listener).actionPerformed(this, args);
break;
case Event.PRESS:
if (listener instanceof PressListener)
((PressListener)listener).actionPerformed(this, args);
break;
case Event.ALL:
listener.actionPerformed(this, args);
break;
}
}
}
| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| java.util.Observer | 零依賴、標準化 | 需繼承類、無事件過濾、已棄用 (Java 9+) | 簡單、單一事件類型的通知 |
| 自定義 Listener | 支援事件過濾、介面導向、無繼承限制 | 需自行維護框架代碼 | 複雜業務、多事件類型、需解耦 |
現代開發中,推薦使用 ApplicationEventPublisher (Spring) 或 EventBus (Guava/GreenRobot) 等成熟事件總線框架,它們提供了異步、註解驅動、線程池隔離等企業級特性。