使用单例模式+观察者模式实现参数配置实时更新
使用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
中根据指定的比较逻辑对观察者进行排序。这样做可以确保观察者在集合中以特定的顺序存储,并且在通知观察者时按照指定的顺序进行遍历。
需要注意的是,由于比较的是观察者对象的地址而不是函数对象本身,因此在使用这种比较器时需要小心。确保观察者对象的生命周期足够长,以便比较其地址的有效性。