文章目錄
- 一、觀察者模式概述
- 二、傳統代碼 vs 觀察者模式對比
- 1. 傳統實現(緊耦合)
- 2. 觀察者模式實現(松耦合)
- 三、Mermaid 類圖說明
- 四、核心設計要點
- 1. 接口分層設計
- 2. 通知機制實現
- 3. 擴展性驗證
- 五、應用場景與注意事項
- 適用場景
- 注意事項
- 1. 內存管理:需注意觀察者生命周期管理,避免野指針
- 2. 通知順序:觀察者列表順序可能影響業務邏輯
- 3. 線程安全:多線程環境下需考慮同步機制
- 4. 異常處理:單個觀察者異常不應影響整體通知流程
- 六、現代C++改進方案
- 七、總結
一、觀察者模式概述
觀察者模式(Observer Pattern)是一種行為型設計模式,用于建立對象間的一對多依賴關系。當一個對象(被觀察者)狀態發生變化時,所有依賴它的對象(觀察者)都會自動收到通知并更新。這種模式通過解耦通知方與接收方,實現了系統的靈活性和可擴展性。
二、傳統代碼 vs 觀察者模式對比
1. 傳統實現(緊耦合)
// 抽象顯示元素接口,強制子類實現 display 方法
class DisplayElement {
public:virtual void display() = 0;
};// 具體顯示類:直接綁定 WeatherData 數據
class CurrentConditionsDisplay : public DisplayElement {
public:// 接收 WeatherData 的更新數據并刷新顯示void update(float temp, float humidity, float pressure) {this->temp = temp;this->humidity = humidity;this->pressure = pressure;display(); // 調用 display 展示最新數據}void display() override {std::cout << "Current conditions: " << temp << "F degrees and " << humidity << "% humidity" << std::endl;}private:float temp, humidity, pressure;
};// 被觀察者類:直接持有顯示對象(緊耦合)
class WeatherData {
public:// 設置天氣數據并直接觸發顯示更新void setMeasurements(float temp, float humidity, float pressure) {this->temp = temp;this->humidity = humidity;this->pressure = pressure;// ??直接調用具體觀察者方法,形成硬編碼依賴currentDisplay.update(temp, humidity, pressure);}private:CurrentConditionsDisplay currentDisplay; // ??硬編碼依賴具體觀察者float temp, humidity, pressure;
};
問題分析:
- 緊耦合問題:
WeatherData
需要直接包含具體觀察者類(如CurrentConditionsDisplay
) - 擴展困難:添加新觀察者需要修改
WeatherData
類 - 違反開閉原則:系統難以對擴展開放,對修改關閉
2. 觀察者模式實現(松耦合)
// 抽象觀察者接口:定義統一的更新協議
class IObserver {
public:// 純虛函數:子類必須實現 update 方法virtual void update(float temp, float humidity, float pressure) = 0;virtual ~IObserver() = default; // 虛析構確保多態釋放
};// 抽象被觀察者接口:定義觀察者管理操作
class ISubject {
public:// 注冊觀察者virtual void registerObserver(IObserver* observer) = 0;// 移除觀察者virtual void removeObserver(IObserver* observer) = 0;// 通知所有觀察者virtual void notifyObservers() = 0;
};// 具體被觀察者實現
class WeatherData : public ISubject {
public:// 實現注冊觀察者方法void registerObserver(IObserver* observer) override {observers.push_back(observer); // 將觀察者加入列表}// 實現移除觀察者方法void removeObserver(IObserver* observer) override {// 使用 std::remove 重排容器,然后 erase 刪除observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());}// 實現通知觀察者方法void notifyObservers() override {for (auto& observer : observers) {observer->update(temp, humidity, pressure); // 通過接口調用更新}}// 設置天氣數據并觸發通知void setMeasurements(float temp, float humidity, float pressure) {this->temp = temp;this->humidity = humidity;this->pressure = pressure;measurementsChanged(); // 觸發狀態變化通知}private:// 狀態變化時調用通知邏輯void measurementsChanged() {notifyObservers(); // 通知所有注冊觀察者}std::vector<IObserver*> observers; // 存儲觀察者指針列表float temp, humidity, pressure;
};// 具體觀察者實現
class CurrentConditionsDisplay : public IObserver {
public:// 構造函數自動注冊到 WeatherDataCurrentConditionsDisplay(WeatherData& weatherData) {this->weatherData.registerObserver(this); // 將自身注冊為觀察者}// 實現 update 方法void update(float temp, float humidity, float pressure) override {this->temp = temp;this->humidity = humidity;this->pressure = pressure;display(); // 刷新顯示}void display() {std::cout << "Current conditions: " << temp << "F degrees and " << humidity << "% humidity" << std::endl;}private:float temp, humidity, pressure;WeatherData& weatherData; // 引用 WeatherData 實例
};
(一堆觀察者,一堆被觀察者,一堆接口;被觀察者提供觀察者注冊、解綁、通知接口,被觀察者提供數據更新并通知方法;觀察者實現被觀察者注冊構造方法,實現更新接口,實現展示方法)
改進優勢:
- 松耦合:
WeatherData
只依賴抽象接口IObserver
- 可擴展性強:新增觀察者只需實現
IObserver
接口 - 符合開閉原則:無需修改
WeatherData
即可擴展功能
三、Mermaid 類圖說明
四、核心設計要點
1. 接口分層設計
- ISubject 接口:定義觀察者管理方法(注冊/移除/通知)
- IObserver 接口:定義更新方法的標準化協議
- 具體實現類:通過組合方式實現接口協作
2. 通知機制實現
void WeatherData::notifyObservers() {for (auto& observer : observers) {observer->update(temp, humidity, pressure); // 通過接口調用具體實現}
}
- 使用迭代器遍歷觀察者列表
- 通過統一接口調用更新方法
- 實現"廣播-訂閱"通信模式
3. 擴展性驗證
新增統計顯示觀察者只需:
class StatisticsDisplay : public IObserver {
public:void update(float temp, float humidity, float pressure) override {temps.push_back(temp);// 計算統計信息...display();}void display() {std::cout << "Stats: Max/Min/Avg temperature..." << std::endl;}
private:std::vector<float> temps;
};
無需修改 WeatherData 類即可實現功能擴展
五、應用場景與注意事項
適用場景
- GUI 事件處理系統(如按鈕點擊事件)
- 實時數據監控系統
- 分布式事件總線架構
- 游戲中的事件驅動系統
注意事項
1. 內存管理:需注意觀察者生命周期管理,避免野指針
2. 通知順序:觀察者列表順序可能影響業務邏輯
3. 線程安全:多線程環境下需考慮同步機制
4. 異常處理:單個觀察者異常不應影響整體通知流程
六、現代C++改進方案
使用智能指針和lambda表達式增強安全性:
class ModernWeatherData : public ISubject {
public:void registerObserver(std::shared_ptr<IObserver> observer) override {observers.push_back(observer); // 使用智能指針避免內存泄漏}// ...其他方法...
private:std::vector<std::shared_ptr<IObserver>> observers; // 智能指針容器
};
七、總結
特性 | 傳統實現 | 觀察者模式 |
---|---|---|
對象耦合度 | 高 | 低 |
擴展性 | 需修改現有代碼 | 支持開閉原則 |
維護成本 | 高 | 低 |
通知靈活性 | 固定調用 | 動態注冊/注銷 |
適用場景復雜度 | 簡單場景 | 復雜系統架構 |
觀察者模式通過接口抽象和行為封裝,為復雜系統提供了優雅的通信解決方案。在C++中實現時需注意接口設計規范、內存管理和線程安全等工程實踐問題,合理使用智能指針和現代C++特性可進一步提升代碼質量。