一、模式結構
觀察者模式包含以下四個角色:
- Subject(主題/被觀察者)
- 維護觀察者列表,提供注冊(
registerObserver
)、移除(removeObserver
)觀察者的方法,并定義通知所有觀察者的方法(notifyObservers
)。 - 示例:天氣數據(
WeatherData
)、優衣庫品牌決策(UniqloBrandDecision
)。
- 維護觀察者列表,提供注冊(
- Observer(觀察者)
- 定義更新接口(
update
),用于接收主題的通知并執行響應邏輯。 - 示例:天氣顯示組件(
CurrentConditionsDisplay
)、消費者(Consumer
)。
- 定義更新接口(
- ConcreteSubject(具體主題)
- 實現主題接口,管理觀察者列表,并在狀態變化時觸發通知。例如,
WeatherData
類在溫度、濕度等數據更新時調用notifyObservers
。
- 實現主題接口,管理觀察者列表,并在狀態變化時觸發通知。例如,
- ConcreteObserver(具體觀察者)
- 實現觀察者接口,定義具體響應邏輯。例如,
CurrentConditionsDisplay
在接收到數據后更新顯示內容。
- 實現觀察者接口,定義具體響應邏輯。例如,
二、核心實現步驟
- 定義觀察者接口:聲明
update
方法,參數可為數據對象或主題引用(推模型或拉模型)。 - 實現具體觀察者:在
update
方法中處理主題狀態變化,例如更新UI或執行業務邏輯。 - 定義主題接口:包含觀察者管理方法和通知方法。
- 實現具體主題:維護觀察者列表,在狀態變化時遍歷并調用
update
方法。
三、代碼示例(氣象站系統)
// 觀察者接口
public interface Observer {void update(float temp, float humidity, float pressure);
}
// 主題接口
public interface Subject {void registerObserver(Observer o);void removeObserver(Observer o);void notifyObservers();
}
// 具體主題類(天氣數據)
public class WeatherData implements Subject {private List observers = new ArrayList<>();private float temperature, humidity, pressure;@Overridepublic void registerObserver(Observer o) { observers.add(o); }@Overridepublic void removeObserver(Observer o) { observers.remove(o); }@Overridepublic void notifyObservers() {for (Observer o : observers) {o.update(temperature, humidity, pressure);}}public void measurementsChanged() {notifyObservers();}public void setMeasurements(float temp, float humidity, float pressure) {this.temperature = temp;this.humidity = humidity;this.pressure = pressure;measurementsChanged();}
}
// 具體觀察者類(當前天氣顯示)
public class CurrentConditionsDisplay implements Observer {private float temp, humidity;@Overridepublic void update(float temp, float humidity, float pressure) {this.temp = temp;this.humidity = humidity;display();}private void display() {System.out.println("當前溫度:" + temp + "℃,濕度:" + humidity + "%");}
}
四、適用場景
- 事件驅動系統:如GUI事件處理、按鈕點擊監聽。
- 實時數據監控:股票價格變動、傳感器數據更新。
- 訂閱/發布模型:郵件訂閱、RSS訂閱、消息隊列。
- 跨模塊通知:訂單狀態變更通知多個服務。
五、優缺點分析
優點 | 缺點 |
---|---|
- 解耦主題與觀察者,符合開閉原則。 | - 觀察者過多時性能下降。 |
- 動態擴展觀察者,無需修改核心邏輯。 | - 通知順序不可控,可能引發依賴鏈問題。 |
- 支持廣播通信,實現事件驅動機制。 | - 循環依賴可能導致棧溢出。 |
六、高級應用與優化
- 異步通知:使用線程池處理觀察者回調,避免阻塞主題線程。
- 事件參數化:通過事件對象(如
VoteEvent
)傳遞具體數據,增強靈活性。 - 弱引用機制:防止內存泄漏(如使用
WeakReference
存儲觀察者)。 - 分布式擴展:結合消息隊列(如Kafka)實現跨進程觀察者。
七、Java內置支持(已過時)
JDK提供java.util.Observable
和Observer
類,但因設計缺陷(如需手動調用setChanged()
)已被標記為過時。推薦自定義實現或使用現代框架(如Spring的ApplicationEvent
)。
總結
觀察者模式通過解耦主題與觀察者,實現了靈活的通知機制,廣泛應用于事件驅動、實時監控等場景。開發者需權衡性能與擴展性,合理設計通知模型(推/拉)和生命周期管理。