觀察者模式又稱「發布-訂閱」,定義物件間一對多依賴:當主題狀態改變,自動通知所有觀察者。核心在於解耦主題與觀察者,支援動態訂閱/取消訂閱。
| 角色 | 說明 | 對應類別 |
|---|---|---|
| Subject (抽象主題) | 管理觀察者集合,提供註冊/移除/通知介面 | Watched 介面 |
| Observer (抽象觀察者) | 定義更新介面 | Watcher 介面 |
| ConcreteSubject (具體主題) | 實作主題邏輯,狀態變更時通知 | ConcreteWatched |
| ConcreteObserver (具體觀察者) | 實作更新邏輯,同步主題狀態 | ConcreteWatcher |
registerObserver() 將自己加入主題列表。notifyObservers()。update()。removeObserver() 取消訂閱。// 1. 抽象主題
interface Watched {
void registerSubscriber(Watcher watcher);
void removeSubscriber(Watcher watcher);
void sendNews();
}
// 2. 抽象觀察者
interface Watcher {
void updateNews();
}
// 3. 具體主題
class ConcreteWatched implements Watched {
private final List subscribers = new ArrayList<>();
@Override public void registerSubscriber(Watcher w) { subscribers.add(w); }
@Override public void removeSubscriber(Watcher w) { subscribers.remove(w); }
@Override public void sendNews() {
System.out.println("開始推送新聞...");
for (Watcher w : subscribers) w.updateNews();
System.out.println("推送結束。");
}
}
// 4. 具體觀察者
class ConcreteWatcher implements Watcher {
private final String name;
public ConcreteWatcher(String name) { this.name = name; }
@Override public void updateNews() { System.out.println(name + " 收到最新新聞!"); }
}
// 5. 測試
public class ObserverDemo {
public static void main(String[] args) {
ConcreteWatched news = new ConcreteWatched();
news.registerSubscriber(new ConcreteWatcher("讀者A"));
news.registerSubscriber(new ConcreteWatcher("讀者B"));
news.registerSubscriber(new ConcreteWatcher("讀者C"));
news.sendNews();
System.out.println("--- 讀者A 取消訂閱 ---");
news.removeSubscriber(new ConcreteWatcher("讀者A")); // 注意:需保留引用才能移除
news.sendNews();
}
}
new ConcreteWatcher("讀者A") 建立新物件無法移除,實務應保留變數或用 ID 對應。subscribers 應用 CopyOnWriteArrayList 或同步鎖。ExecutorService 非阻塞通知。WeakReference<Watcher>。java.util.Observable / Observer(Java 9 棄用,因設計缺陷)。PropertyChangeListener、EventListener、Guava EventBus、Spring ApplicationEventPublisher、RxJava Observable 等成熟事件總線。觀察者模式是「鬆耦合、高擴展」的經典範例。掌握其核心結構、避開常見坑點(引用管理、執行緒安全、異步處理),並善用成熟框架而非重造輪子,是架構師的必修功課。