使用单例模式+观察者模式实现参数配置实时更新

使用vector存储观察者列表

cpp 复制代码
#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存储观察者列表

cpp 复制代码
#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 中根据指定的比较逻辑对观察者进行排序。这样做可以确保观察者在集合中以特定的顺序存储,并且在通知观察者时按照指定的顺序进行遍历。

需要注意的是,由于比较的是观察者对象的地址而不是函数对象本身,因此在使用这种比较器时需要小心。确保观察者对象的生命周期足够长,以便比较其地址的有效性。

相关推荐
东风吹柳9 小时前
观察者模式(sigslot in C++)
c++·观察者模式·信号槽·sigslot
T1an-114 小时前
设计模式之【观察者模式】
观察者模式·设计模式
重生之我在字节当程序员19 小时前
如何实现单例模式?
单例模式
夕泠爱吃糖19 小时前
如何实现单例模式?
单例模式
m0_6075487619 小时前
什么是单例模式
开发语言·javascript·单例模式
Am心若依旧40919 小时前
[c++进阶(三)]单例模式及特殊类的设计
java·c++·单例模式
因特麦克斯19 小时前
如何实现对象的克隆?如何实现单例模式?
c++·单例模式
狐拾叁4 天前
设计模式-创建者模式-单例模式(java版)
java·单例模式·设计模式
benben0444 天前
Unity3D仿星露谷物语开发5之角色单例模式
unity·单例模式·游戏引擎
真想骂*4 天前
观察者模式:它究竟在观察什么?
java·开发语言·观察者模式