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

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

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

相关推荐
软件黑马王子15 小时前
3.单例模式问题1:构造函数
开发语言·单例模式·c#
软件黑马王子16 小时前
4.单例模式问题2:重复挂载
开发语言·单例模式·c#
软件黑马王子17 小时前
5.单例模式问题3:多线程问题
单例模式·前端框架·c#
Java后端的Ai之路2 天前
17、Python - 观察者模式
开发语言·人工智能·python·观察者模式·外观模式
WarPigs3 天前
观察者模式笔记
观察者模式
旧梦95274 天前
Java 单例模式:从基础到实战的完整指南
java·开发语言·单例模式
码匠许师傅5 天前
【设计模式精讲】4.单例模式(Singleton)
c++·单例模式·设计模式
米啦啦.7 天前
设计模式/
观察者模式·单例模式·设计模式·工厂模式
布莱克6057 天前
单例模式详解:什么是单例模式,它能解决哪些问题?
开发语言·qt·单例模式
拓人间精准客7 天前
ToB 销售获客避坑指南:如何用全维度大数据实现降本增效
大数据·数据结构·单例模式