首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ 設計模式實戰:觀察者模式完整實作與解析

     編輯:關於C++

模式動機:解耦主題與觀察者

觀察者模式定義物件間一對多依賴,當主題狀態改變時,自動通知所有已註冊觀察者。此模式廣泛應用於事件處理系統、MVC 架構的 Model-View 同步、訊息推播等場景。C++ 雖無介面關鍵字,但可用純虛函數抽象類別模擬介面,配合多型實現靈活的訂閱/發布機制。

核心類別結構設計

// 前向宣告
class Observer;
class Subject;

// 主題抽象介面
class Subject {
public:
    virtual ~Subject() = default;
    virtual void attach(Observer* o) = 0;      // 訂閱
    virtual void detach(Observer* o) = 0;      // 退訂 (補充)
    virtual void notify() = 0;                 // 通知所有觀察者
    virtual void setWeather(const std::string& str) = 0;
    virtual std::string getWeather() const = 0;
};

// 觀察者抽象介面
class Observer {
public:
    virtual ~Observer() = default;
    virtual std::string getName() const = 0;
    virtual void update(Subject* s) = 0;       // 接收通知
};

具體主題:氣象站


class WeatherStation : public Subject {
private:
    std::string weather_;
    std::list observers_;

public:
    void attach(Observer* o) override {
        observers_.push_back(o);
    }
    void detach(Observer* o) override {
        observers_.remove(o);
    }
    void notify() override {
        for (auto* obs : observers_) {
            obs->update(this);
        }
    }
    void setWeather(const std::string& str) override {
        weather_ = str;
        notify();  // 狀態變更即通知
    }
    std::string getWeather() const override { return weather_; }
};

具體觀察者:衛星接收端


class Satellite : public Observer {
private:
    std::string name_;

public:
    explicit Satellite(const std::string& name) : name_(name) {}
    std::string getName() const override { return name_; }
    void update(Subject* s) override {
        std::cout << name_ << " 收到天氣更新: " << s->getWeather() << '\n';
    }
};

客戶端測試程式


int main() {
    WeatherStation station;

    // 建立四顆衛星觀察者
    Satellite s1("風雲一號"), s2("風雲二號"), s3("風雲三號"), s4("風雲四號");

    // 訂閱
    station.attach(&s1);
    station.attach(&s2);
    station.attach(&s3);
    station.attach(&s4);

    // 模擬天氣變化
    station.setWeather("晴朗");
    station.setWeather("雷陣雨");
    station.setWeather("多雲");

    return 0;
}

執行結果


風雲一號 收到天氣更新: 晴朗
風雲二號 收到天氣更新: 晴朗
風雲三號 收到天氣更新: 晴朗
風雲四號 收到天氣更新: 晴朗
風雲一號 收到天氣更新: 雷陣雨
風雲二號 收到天氣更新: 雷陣雨
風雲三號 收到天氣更新: 雷陣雨
風雲四號 收到天氣更新: 雷陣雨
風雲一號 收到天氣更新: 多雲
風雲二號 收到天氣更新: 多雲
風雲三號 收到天氣更新: 多雲
風雲四號 收到天氣更新: 多雲

關鍵實作細節與最佳實務

  • 虛構函數:抽象基類必須宣告虛構函數,確保正確釋放衍生類資源。
  • 觀察者容器:使用 std::list 或 std::vector 儲存觀察者指標;list 適合頻繁增刪,vector 遍歷較快。
  • 生命週期管理:主題不擁有觀察者記憶體,觀察者由客戶端管理。若主題需管理生命週期,可改用 std::shared_ptr<Observer>。
  • 執行緒安全:多執行緒環境下需加鎖保護 observers_ 容器,或使用無鎖資料結構。
  • 推 vs 拉模型:範例採拉模型 (觀察者呼叫 getWeather() 取資料);若資料量大,可改推模型 直接在 update 參數傳遞資料。

擴充應用:支援多種氣象資料


struct WeatherData {
    float temperature;
    float humidity;
    float pressure;
};

class AdvancedStation : public Subject {
    WeatherData data_;
    std::list obs_;
public:
    void setData(const WeatherData& d) { data_ = d; notify(); }
    const WeatherData& getData() const { return data_; }
    // ... attach/detach/notify 同前
};

class DisplayBoard : public Observer {
    void update(Subject* s) override {
        auto* station = dynamic_cast(s);
        if (station) {
            auto d = station->getData();
            std::cout << "溫度:" << d.temperature << " 濕度:" << d.humidity << '\n';
        }
    }
};

總結

觀察者模式以抽象介面解耦主題與觀察者,實現動態訂閱與廣播通知。C++ 透過純虛函數與多型優雅實現此模式,配合標準庫容器與智慧指標,可構建健壯、可擴充的事件驅動系統。掌握其核心結構與變體 (推/拉、執行緒安全、生命週期策略) 是 C++ 架構師必備技能。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved