觀察者模式定義對象間的一對多依賴,當主題狀態改變時,自動通知所有觀察者。Java 在 java.util 包中提供了 Observable 類與 Observer 接口,開箱即用,無需第三方庫。本文通過兩個完整案例演示其核心用法與進階技巧。
| 角色 | 類/介面 | 關鍵方法 |
|---|---|---|
| 被觀察者 | Observable | addObserver()、setChanged()、notifyObservers() |
| 觀察者 | Observer | update(Observable o, Object arg) |
關鍵點: 必須先調用 setChanged() 設置內部標誌位,notifyObservers() 才會真正觸發觀察者的 update()。此設計避免無效通知。
NumObservable 封裝整數 data,setData() 修改值後發送通知;NumObserver 接收並打印新值。
// 被觀察者
public class NumObservable extends Observable {
private int data = 0;
public void setData(int i) {
data = i;
setChanged();
notifyObservers(); // arg 為 null
}
}
// 觀察者
public class NumObserver implements Observer {
public void update(Observable o, Object arg) {
NumObservable src = (NumObservable) o;
System.out.println("Data changed to " + src.getData());
}
}
測試輸出:Data changed to 1 / 2 / 3
業務常見需求:不同觀察者關注不同事件類型。利用 notifyObservers(Object arg) 傳遞標識,觀察者內部過濾。
public class NumsObservable extends Observable {
public static final Integer ODD = 1, EVEN = 2;
public void setData(int i) {
data = i;
Integer flag = (i & 0x0001) == 1 ? ODD : EVEN;
setChanged();
notifyObservers(flag); // 攜帶奇偶標識
}
}
public class OddObserver implements Observer {
public void update(Observable o, Object arg) {
if (arg == NumsObservable.ODD) { // 僅處理奇數
System.out.println("OddObserver: " + ((NumsObservable)o).getData());
}
}
}
測試中註冊 OddObserver 與 EvenObserver,輸出精準分流:Odd:1 / Even:2 / Odd:3。
setChanged():漏調是新手最常見錯誤,導致通知靜默失效。arg:避免觀察者修改共享狀態引發併發問題。deleteObserver() 防止內存洩漏,尤其在生命週期不一致的組件間。PropertyChangeListener、Guava EventBus 或 Reactive Streams(RxJava/Project Reactor)獲得更強大的異步、背壓支持。