使用vector存儲觀察者列表
#include <iostream>
#include <vector>
#include <functional>
#include <algorithm>// 配置參數結構體
struct MyConfigStruct {int parameter1;std::string parameter2;
};class Config {
public:using Observer = std::function<void(const MyConfigStruct&)>;static Config& getInstance() {static Config instance;return instance;}// 注冊觀察者void registerObserver(Observer observer) {observers_.push_back(observer);}// 移除觀察者void removeObserver(Observer observer) {observers_.erase(std::remove_if(observers_.begin(), observers_.end(),[observer](const Observer& o) {return o.target_type() == observer.target_type();}), observers_.end());}/*void removeObserver(Observer observer) {auto it = std::find_if(observers_.begin(), observers_.end(),[observer](const Observer& o) {return &o == &observer;});if (it != observers_.end()) {observers_.erase(it);}}*/// Setter方法用于修改配置參數的值void setParameters(const MyConfigStruct& newParameters) {parameters_ = newParameters;notifyObservers();}private:Config() {// 初始化配置參數parameters_ = { 0, "" };}// 配置參數MyConfigStruct parameters_;// 觀察者集合std::vector<Observer> observers_;// 通知觀察者void notifyObservers() {for (const auto& observer : observers_) {observer(parameters_);}}
};// 模塊A作為觀察者,處理參數變化的通知
class ModuleA {
public:void handleConfigUpdate(const MyConfigStruct& config) {std::cout << "Module A: Parameter 1 = " << config.parameter1 << ", Parameter 2 = " << config.parameter2 << std::endl;}
};// 模塊B作為觀察者,處理參數變化的通知
class ModuleB {
public:void handleConfigUpdate(const MyConfigStruct& config) {std::cout << "Module B: Parameter 1 = " << config.parameter1 << ", Parameter 2 = " << config.parameter2 << std::endl;}
};int main() {// 創建配置實例和模塊實例Config& config = Config::getInstance();ModuleA moduleA;ModuleB moduleB;// 注冊觀察者config.registerObserver([&moduleA](const MyConfigStruct& config) {moduleA.handleConfigUpdate(config);});config.registerObserver([&moduleB](const MyConfigStruct& config) {moduleB.handleConfigUpdate(config);});// 更新配置參數MyConfigStruct newParameters{ 42, "Hello World" };config.setParameters(newParameters);// 移除觀察者config.removeObserver([&moduleA](const MyConfigStruct& config) {moduleA.handleConfigUpdate(config);});// 再次更新配置參數MyConfigStruct newParameters2{ 100, "Goodbye" };config.setParameters(newParameters2);return 0;
}
輸出結果
Module A: Parameter 1 = 42, Parameter 2 = Hello World
Module B: Parameter 1 = 42, Parameter 2 = Hello World
Module A: Parameter 1 = 100, Parameter 2 = Goodbye
Module B: Parameter 1 = 100, Parameter 2 = Goodbye
在 removeObserver
方法中,我們使用了 std::remove_if
來查找并移除與指定觀察者對象類型相同的觀察者。通過比較 o.target_type()
和 observer.target_type()
可以判斷兩個觀察者對象的類型是否相同。
在 C++ 中,std::function
是一個通用的函數封裝器,可以包裝任意可調用對象(如函數指針、函數對象、Lambda 表達式等)。為了允許運行時檢查 std::function 所包裝的具體函數對象類型,C++ 提供了 target_type()
成員函數來獲取存儲的函數對象類型信息。
在上述代碼中,我們使用 o.target_type()
和 observer.target_type()
來比較兩個觀察者對象的函數對象類型是否相同。這樣做是為了確保移除與指定觀察者對象類型相同的觀察者。
請注意,target_type()
返回的是 std::type_info
對象的指針,而不是直接的類型。因此,我們使用 == 運算符來比較兩個 std::type_info
對象的指針是否相等,以判斷兩個觀察者對象的函數對象類型是否相同。
使用set存儲觀察者列表
#include <iostream>
#include <set>
#include <functional>// 配置參數結構體
struct MyConfigStruct {int parameter1;std::string parameter2;
};class Config {
public:using Observer = std::function<void(const MyConfigStruct&)>;static Config& getInstance() {static Config instance;return instance;}// 注冊觀察者void registerObserver(Observer observer) {observers_.insert(observer);}// 移除觀察者void removeObserver(Observer observer) {observers_.erase(observer);}// Setter方法用于修改配置參數的值void setParameters(const MyConfigStruct& newParameters) {parameters_ = newParameters;notifyObservers();}private:Config() {// 初始化配置參數parameters_ = { 0, "" };}// 配置參數MyConfigStruct parameters_;// 比較函數對象,用于在集合中排序觀察者struct ObserverComparator {bool operator()(const Observer& lhs, const Observer& rhs) const {// 在這里實現你需要的比較邏輯// 這里簡單地使用內存地址進行比較return &lhs < &rhs;}};// 觀察者集合std::set<Observer, ObserverComparator> observers_;// 通知觀察者void notifyObservers() {for (const auto& observer : observers_) {observer(parameters_);}}
};// 模塊A作為觀察者,處理參數變化的通知
class ModuleA {
public:void handleConfigUpdate(const MyConfigStruct& config) {std::cout << "Module A: Parameter 1 = " << config.parameter1 << ", Parameter 2 = " << config.parameter2 << std::endl;}
};// 模塊B作為觀察者,處理參數變化的通知
class ModuleB {
public:void handleConfigUpdate(const MyConfigStruct& config) {std::cout << "Module B: Parameter 1 = " << config.parameter1 << ", Parameter 2 = " << config.parameter2 << std::endl;}
};int main() {// 創建配置實例和模塊實例Config& config = Config::getInstance();ModuleA moduleA;ModuleB moduleB;// 注冊觀察者config.registerObserver([&moduleA](const MyConfigStruct& config) {moduleA.handleConfigUpdate(config);});config.registerObserver([&moduleB](const MyConfigStruct& config) {moduleB.handleConfigUpdate(config);});// 更新配置參數MyConfigStruct newParameters{ 42, "Hello World" };config.setParameters(newParameters);// 移除觀察者config.removeObserver([&moduleA](const MyConfigStruct& config) {moduleA.handleConfigUpdate(config);});// 再次更新配置參數MyConfigStruct newParameters2{ 100, "Goodbye" };config.setParameters(newParameters2);return 0;
}
同樣的輸出結果
Module A: Parameter 1 = 42, Parameter 2 = Hello World
Module B: Parameter 1 = 42, Parameter 2 = Hello World
Module A: Parameter 1 = 100, Parameter 2 = Goodbye
Module B: Parameter 1 = 100, Parameter 2 = Goodbye
在上述代碼中,ObserverComparator
是一個用于比較觀察者對象的比較器結構體。它實現了一個 operator()
函數,該函數接受兩個觀察者對象作為參數,并返回一個布爾值來表示它們的相對順序。
在這個比較器中,我們簡單地使用觀察者對象的內存地址進行比較。如果 &lhs
小于 &rhs
,則認為 lhs
在集合中應該排在 rhs
的前面,返回 true
。否則,返回 false
。
通過使用自定義的比較器,我們可以在 std::set
中根據指定的比較邏輯對觀察者進行排序。這樣做可以確保觀察者在集合中以特定的順序存儲,并且在通知觀察者時按照指定的順序進行遍歷。
需要注意的是,由于比較的是觀察者對象的地址而不是函數對象本身,因此在使用這種比較器時需要小心。確保觀察者對象的生命周期足夠長,以便比較其地址的有效性。