Observer觀察者模式
- 模式定義
- 動機(Motivation)
- 結構(Structure)
- 應用場景一(氣象站)實現步驟
- 1.定義觀察者接口
- 2.定義被觀察者(主題)接口
- 3.實現具體被觀察者對象(氣象站)
- 4.實現具體觀察者(例如:顯示屏)
- 5.main.cpp中使用示例
- 6.輸出結果
- 7. 關鍵點
- 應用場景二(溫度傳感器)實現步驟
- 1.定義觀察者接口
- 2.定義被觀察者接口
- 3.實現具體被觀察者(溫度傳感器)
- 4.實現具體觀察者(溫度顯示屏)
- 5.使用示例
- 要點總結
模式定義
觀察者模式:定義對象間的一種一對多(變化)的依賴關系,以便當一個對象(Subject)的狀態發生改變時,所有依賴于它的對象都得到通知并自動更新。
允許對象(觀察者)訂閱另一個對象(被觀察者)的狀態變化,并在狀態變化時自動接收通知。
動機(Motivation)
- 在軟件構建過程中,我們需要為某些對象建立一種“通知依賴關系”——一個對象(目標對象)的狀態發送改變,所有的依賴對象(觀察者對象)都將得到通知。如果這樣的依賴關系過于密切,將使軟件不能很好地抵御變化。
- 使用面向對象技術,可以將這種依賴關系弱化,并形成一種穩定的依賴關系。從而實現軟件體系結構的松耦合。
結構(Structure)
應用場景一(氣象站)實現步驟
1.定義觀察者接口
observer.h頭文件
#pragma once
#include<vector>
#include<algorithm>//觀察者接口
class Observer {
public:virtual ~Observer() = default;virtual void update() = 0; //更新方法(純虛函數)
};
2.定義被觀察者(主題)接口
subject.h頭文件
#pragma once
#include "observer.h"class Subject {
public:virtual ~Subject() = default;virtual void attach(Observer*observer) = 0; //注冊觀察者virtual void detach(Observer*observer) = 0; //移除觀察者virtual void notify() = 0; //通知觀察者protected:std::vector<Observer*> observers_; //存儲觀察則列表
};
3.實現具體被觀察者對象(氣象站)
concretesubject.h
#pragma once
#include"subject.h"class WeatherStation :public Subject {
public://注冊觀察者void attach(Observer* observer)override {observers_.push_back(observer);}//移除觀察者void detach(Observer*observer)override {auto it = std::remove(observers_.begin(), observers_.end(), observer);observers_.erase(it, observers_.end());}//通知所有觀察者void notify()override {for (auto observer : observers_) {observer->update();}}//更新氣象數據并觸發通知void setMeasurements(float temperature, float humidity) {temperature_ = temperature;humidity_ = humidity;notify(); //數據變化時通知觀察者}//獲取數據(供觀察者拉取)float getTemperature()const { return temperature_; }float getHumidity()const { return humidity_; }private:float temperature_ = 0.0f;float humidity_ = 0.0f;
};
4.實現具體觀察者(例如:顯示屏)
concreteobserver.h
#pragma once
#include<iostream>
#include"observer.h"
#include"concretesubject.h"
class Display :public Observer {
public:explicit Display(WeatherStation&station):station_(station){}//當被觀察者通知時,更新顯示void update()override {std::cout << "Temperature: " << station_.getTemperature()<< " ℃,Humidity : " << station_.getHumidity() << "% \n";}
private:WeatherStation& station_;
};
5.main.cpp中使用示例
#include <iostream>
#include"concretesubject.h"
#include"concreteobserver.h"int main()
{WeatherStation station; // 被觀察者(氣象站)Display display1(station); // 觀察者1(顯示屏)Display display2(station); // 觀察者2// 注冊觀察者station.attach(&display1);station.attach(&display2);// 更新數據,自動觸發觀察者更新station.setMeasurements(25.5f, 60.0f);station.setMeasurements(26.0f, 55.0f);// 移除一個觀察者station.detach(&display2);station.setMeasurements(27.0f, 50.0f);return 0;
}
6.輸出結果
Temperature: 25.5 ℃,Humidity : 60%
Temperature: 25.5 ℃,Humidity : 60%
Temperature: 26 ℃,Humidity : 55%
Temperature: 26 ℃,Humidity : 55%
Temperature: 27 ℃,Humidity : 50%
7. 關鍵點
-
松耦合:觀察者和被觀察者通過接口交互,無需知道彼此的具體實現。
-
推拉模型:
-
推模式:被觀察者將數據直接推送給觀察者(通過 update 方法參數)。
-
拉模式:觀察者主動從被觀察者拉取數據(本例中使用 getTemperature() 和 getHumidity())。
-
-
內存管理:需確保觀察者的生命周期覆蓋被觀察者,或使用 shared_ptr 管理資源。
應用場景二(溫度傳感器)實現步驟
1.定義觀察者接口
observer.h
#pragma once
//定義觀察者接口
class Observer {
public:virtual ~Observer() = default;virtual void update() = 0; //更新方法
};
2.定義被觀察者接口
subject.h
#pragma once
#include"observer.h"
#include<vector>
class Subject {
public:virtual ~Subject() = default;virtual void attach(Observer*observer) = 0; //注冊觀察者virtual void detach(Observer*observer) = 0; //移除觀察者virtual void notify() = 0; //通知觀察者
protected:std::vector<Observer*>observers_;
};
3.實現具體被觀察者(溫度傳感器)
concretesubject.h
#pragma once
#include"subject.h"
#include <algorithm>class TemperatureSensor :public Subject {
public:void attach(Observer*observer)override {observers_.push_back(observer);}void detach(Observer* observer) override {auto it = std::remove(observers_.begin(), observers_.end(), observer);observers_.erase(it, observers_.end());}void notify() override {for (auto observer : observers_) {observer->update();}}void setTemperature(float temp) {temperature_ = temp;notify(); // 溫度變化時通知所有觀察者}float getTemperature() const { return temperature_; }private:float temperature_ = 0.0f;
};
4.實現具體觀察者(溫度顯示屏)
concreteobserver.h
#pragma once
#include"observer.h"
#include "concretesubject.h"
#include<iostream>class TemperatureDisplay :public Observer {
public:explicit TemperatureDisplay(TemperatureSensor&sensor):sensor_(sensor){}void update()override {std::cout << "當前溫度: " << sensor_.getTemperature() << " ℃\n";}
private:TemperatureSensor& sensor_;
};
5.使用示例
#include"concreteobserver.h"
#include"concretesubject.h"int main() {TemperatureSensor sensor;TemperatureDisplay display(sensor);sensor.attach(&display);sensor.setTemperature(25.5f); // 輸出:當前溫度: 25.5°Csensor.detach(&display);sensor.setTemperature(26.0f); // 無輸出return 0;
}
要點總結
- 使用面向對象的抽象,Observer模式使得我們可以獨立地改變目標與觀察者,從而使二者之間的依賴關系達致松耦合。
- 目標發送通知時,無需指定觀察者,通知(可以攜帶通知信息作為參數)會自動傳播。
- 觀察者自己決定是否需要訂閱通知,目標對象對此一無所知。
- Observer模式是基于事件的UI框架中非常常用的設計模式,也是MVC模式的一個重要組成部分。