設計模式是「特定情境下反覆出現問題的文檔化解決方案」。GoF 《設計模式》一書定義的 23 種模式奠基了軟體設計通用語言。本系列從 Java 類庫切入,首篇深度剖析 **Observer 模式** 在 JDK (java.util.Observable/Observer) 的實作細節與應用範例。
典型場景:UI 資料變更同步更新資料庫、資料庫變更自動刷新 UI。
public interface Observer {
void update(Observable o, Object arg); // 狹義應呼叫 o.getX() 取最新狀態
}
| 方法 | 功能 |
|---|---|
addObserver(Observer) | 註冊觀察者至內部 Vector 列表 |
deleteObserver(Observer) | 移除單一觀察者 |
deleteObservers() | 清空所有觀察者 |
countObservers() | 返回註冊數量 |
setChanged() | protected,標記狀態已變更(必須調用,否則通知不發送) |
clearChanged() | protected,清除變更標記(notifyObservers 內自動調用) |
hasChanged() | 檢查是否已變更 |
notifyObservers(Object) | 檢查標記,若已變更則**同步**逐一呼叫 update(),最後清除標記 |
notifyObservers() | 等同 notifyObservers(null) |
同步機制:notifyObservers 為 synchronized,多執行緒環境下順序執行,但可能導致新增觀察者遺漏通知、已移除觀察者仍收到通知。
// Subject:封裝 Observable,轉發註冊與通知
class FrameSubject extends JFrame {
DateSubject subject = new DateSubject(); // 繼承 Observable
public void registerObserver(Observer o) { subject.addObserver(o); }
void onButtonClick() {
subject.setWidthInfo(parseInt(tf1.getText()));
subject.setHeightInfo(parseInt(tf2.getText()));
subject.notifyObservers(); // 發送通知
}
}
// Observable 子類:封裝被觀察資料
class DateSubject extends Observable {
private int width, height;
public void setWidthInfo(int w) { width = w; setChanged(); } // 關鍵:setChanged()
public void setHeightInfo(int h) { height = h; setChanged(); }
public int getWidthInfo() { return width; }
public int getHeightInfo() { return height; }
}
// Observer 實作:接收通知並更新 UI
class FrameObserver extends JFrame implements Observer {
public void update(Observable o, Object arg) {
DateSubject s = (DateSubject) o;
lblWidth.setText(String.valueOf(s.getWidthInfo()));
lblHeight.setText(String.valueOf(s.getHeightInfo()));
}
}
// 啟動
FrameSubject f1 = new FrameSubject();
FrameObserver f2 = new FrameObserver();
f1.registerObserver(f2);
f1.setVisible(true); f2.setVisible(true);
Observable 提供預設通知邏輯,簡化開發。Vector 管理觀察者列表,符合大多數場景。FrameSubject 僅能組合而非繼承)。Observable,複雜場景需自行抽離 Manager 類別解耦。Observer 模式解決物件間**狀態映射/鏡像**問題。JDK 內建實作足應付一般需求,但理解其限制(類別化、同步通知、列表耦合),在需要高擴展性時可自行實作介面化版本。掌握模式語言,能以最小認知負擔溝通複雜設計意圖。