C++利用模板实现消息订阅和分发

news2024/11/23 8:26:51

        解耦是编写程序所遵循的基本原则之一,多态是提高程序灵活性的重要方法。C++语言支持重载,模板,虚函数等特性,为编写高性能可扩展的程序提供了利器。编写大型项目时,免不了需要各个模块之间相互调用,从而产生了模块之间的耦合。不同模块之间的关系称之为耦合,耦合程度由高到底可以分为以下几类:

1. 内容耦合

内容耦合常见情形如下:

1)一个模块直接访问另一个模块的内容

2)一个模块不通过正常入口转到另一个模块

3)两个模块有部分程序代码重叠,常见在汇编语言中

4)一个模块有多个入口

2. 公共耦合

若模块都访问同一个公共数据环境,则称他们是公共耦合。

3. 外部耦合

模块通过非参数传递的方式访问同一个全局变量,则称之为外部耦合。C语言中的extern类型变量就是一种外部耦合。

4. 控制耦合

一个模块通过传送参数和控制信息来选择控制另一个模块的功能,就是控制耦合。控制耦合最常见的方式就是接口调用。

5. 标记耦合

6. 数据耦合

7. 非直接耦合

订阅分发是程序编写常用的设计模式,回调,QT中的信号槽本质都是订阅模式。两个模块之间可以直接交互,也可以借助第三者来实现交互。下面将展示一种借助第三者来实现模块之间的交互。

messager.hpp

#ifndef _SELF_MAMESSAGE__
#define _SELF_MAMESSAGE__

#include <map>
#include <unordered_map>
#include <functional>
#include <string>
#include <vector>
#include <mutex>
#include <atomic>
#include <thread>
#include <condition_variable>

class RWLock {
    std::mutex _mutex;				
    std::condition_variable _readcv, _writecv;
    std::atomic_bool _iswritting;	
    std::atomic_int _readcount;	

public:
    RWLock() : _iswritting(false) , _readcount(0) {}
    void lockr() {
        if(_iswritting)
        {
            _mutex.lock();
        }
        _readcount++;
    }

    void unlockr() {
        _readcount--;
        if(_readcount == 0)
        {
            _mutex.unlock();
        }
    }

    void lockw() {
        if(_iswritting || _readcount != 0)
        {
            _mutex.lock();
        }
        _iswritting = true;
    }

    void unlockw() {
        _iswritting = false;
        _mutex.unlock();
    }
};

class SelfMessager {
public:
    SelfMessager() = delete;
    static void subcribe(const std::string &key, std::function<void()> func) {
        getpubsub_mutex().lockw();
        auto &messager_map = get_messager_map();
        auto &funcs = messager_map[key];
        funcs.push_back(func);
        getpubsub_mutex().unlockw();
    }

    template<typename T>
    static void subcribe(const std::string &key, std::function<void(const T &)> func) {
        getpubsub_mutex_p1().lockw();
        auto &messager_map = get_messager_map<T>();
        auto &funcs = messager_map[key];
        funcs.push_back(func);
        getpubsub_mutex_p1().unlockw();
    }

    template<typename T0, typename T1>
    static void subcribe(const std::string &key, std::function<void(const T0 &, const T1 &)> func) {
        getpubsub_mutex_p2().lockw();
        auto &messager_map = get_messager_map<T0, T1>();
        auto &funcs = messager_map[key];
        funcs.push_back(func);
        getpubsub_mutex_p2().unlockw();
    }

    template<typename T0, typename T1, typename T2>
    static void subcribe(const std::string &key, std::function<void(const T0 &, const T1 &, const T2 &)> func) {
        getpubsub_mutex_p3().lockw();
        auto &messager_map = get_messager_map<T0, T1, T2>();
        auto &funcs = messager_map[key];
        funcs.push_back(func);
        getpubsub_mutex_p3().unlockw();
    }

    template<typename T0, typename T1, typename T2>
    static void subcribe(const std::string &key, std::function<void(const T0 &, const T1 &, T2 &)> func) {
        getpubsub_mutex_p3().lockw();
        auto &messager_map = get_messager_map<T0, T1, T2>();
        auto &funcs = messager_map[key];
        funcs.push_back(func);
        getpubsub_mutex_p3().unlockw();
    }

    template<typename T0, typename T1, typename T2, typename T3>
    static void
    subcribe(const std::string &key, std::function<void(const T0 &, const T1 &, const T2 &, const T3 &)> func) {
        getpubsub_mutex_p4().lockw();
        auto &messager_map = get_messager_map<T0, T1, T2, T3>();
        auto &funcs = messager_map[key];
        funcs.push_back(func);
        getpubsub_mutex_p4().unlockw();
    }

    template<typename T0, typename T1, typename T2, typename T3, typename T4>
    static void subcribe(const std::string &key,
                         std::function<void(const T0 &, const T1 &, const T2 &, const T3 &, const T4 &)> func) {
        getpubsub_mutex_p5().lockw();
        auto &messager_map = get_messager_map<T0, T1, T2, T3, T4>();
        auto &funcs = messager_map[key];
        funcs.push_back(func);
        getpubsub_mutex_p5().unlockw();
    }

    static void publish(const std::string &key) {
        getpubsub_mutex().lockr();
        auto &messager_map = get_messager_map();
        if(messager_map.find(key) == messager_map.end()) {
            return;
        }
        auto &funcs = messager_map[key];
        for (const auto &func : funcs) {
            func();
        }
        getpubsub_mutex().unlockr();
    }

    template<typename T>
    static void publish(const std::string &key, const T &value) {
        getpubsub_mutex_p1().lockr();
        auto &messager_map = get_messager_map<T>();
        if(messager_map.find(key) == messager_map.end()) {
            return;
        }
        auto &funcs = messager_map[key];
        for (const auto &func : funcs) {
            func(value);
        }
        getpubsub_mutex_p1().unlockr();
    }

    template<typename T0, typename T1>
    static void publish(const std::string &key, const T0 &value0, const T1 &value1) {
        getpubsub_mutex_p2().lockr();
        auto &messager_map = get_messager_map<T0, T1>();
        if(messager_map.find(key) == messager_map.end()) {
            return;
        }
        auto &funcs = messager_map[key];
        for (const auto &func : funcs) {
            func(value0, value1);
        }
        getpubsub_mutex_p2().unlockr();
    }

    template<typename T0, typename T1, typename T2>
    static void publish(const std::string &key, const T0 &value0, const T1 &value1, const T2 &value2) {
        getpubsub_mutex_p3().lockr();
        auto &messager_map = get_messager_map<T0, T1, T2>();
        if(messager_map.find(key) == messager_map.end()) {
            return;
        }
        auto &funcs = messager_map[key];
        for (const auto &func : funcs) {
            func(value0, value1, value2);
        }
        getpubsub_mutex_p3().unlockr();
    }

    template<typename T0, typename T1, typename T2, typename T3>
    static void
    publish(const std::string &key, const T0 &value0, const T1 &value1, const T2 &value2, const T3 &value3) {
        getpubsub_mutex_p4().lockr();
        auto &messager_map = get_messager_map<T0, T1, T2, T3>();
        if(messager_map.find(key) == messager_map.end()) {
            return;
        }
        auto &funcs = messager_map[key];
        for (const auto &func : funcs) {
            func(value0, value1, value2, value3);
        }
        getpubsub_mutex_p4().unlockr();
    }

    template<typename T0, typename T1, typename T2, typename T3, typename T4>
    static void publish(const std::string &key, const T0 &value0, const T1 &value1, const T2 &value2, const T3 &value3,
                        const T4 &value4) {
        getpubsub_mutex_p5().lockr();
        auto &messager_map = get_messager_map<T0, T1, T2, T3, T4>();
        if(messager_map.find(key) == messager_map.end()) {
            return;
        }
        auto &funcs = messager_map[key];
        for (const auto &func : funcs) {
            func(value0, value1, value2, value3, value4);
        }
        getpubsub_mutex_p5().unlockr();
    }

    template<typename T>
    static void add_server_func(const std::string &key, std::function<T> func) {
        getserverfunc_mutex().lockw();
        auto &server_func = get_server_func<T>(key);
        if (server_func){
             publish("log_fatal", "server_func is already exists, key: " + key);
             throw std::bad_exception();
        }
        server_func = func;
        getserverfunc_mutex().unlockw();
    }

    template<typename T>
    static bool has_server(const std::string &key) {
        auto &server_func = get_server_func<T>(key);
        if (server_func){
            return true;
        } else {
            return false;
        }
    }

    template<typename T>
    static void remove_server_func(const std::string &key) {
        auto &server_func = get_server_func<T>(key);
        server_func = std::function<T>();
    }

    template<typename T>
    static std::function<T> &get_server_func(const std::string &key) {
        getserverfunc_mutex().lockr();
        auto & server_func_map = get_server_map<T>();
        getserverfunc_mutex().unlockr();
        return server_func_map[key];
    }

public:

    static RWLock& getpubsub_mutex() {
        static RWLock _pubsubmutex;
        return _pubsubmutex;
    }

    static RWLock& getpubsub_mutex_p1() {
        static RWLock _pubsubmutex;
        return _pubsubmutex;
    }

    static RWLock& getpubsub_mutex_p2() {
        static RWLock _pubsubmutex;
        return _pubsubmutex;
    }

    static RWLock& getpubsub_mutex_p3() {
        static RWLock _pubsubmutex;
        return _pubsubmutex;
    }

    static RWLock& getpubsub_mutex_p4() {
        static RWLock _pubsubmutex;
        return _pubsubmutex;
    }

    static RWLock& getpubsub_mutex_p5() {
        static RWLock _pubsubmutex;
        return _pubsubmutex;
    }

    static RWLock& getserverfunc_mutex() {
        static RWLock _serverfuncmutex;
        return _serverfuncmutex;
    }


    template<typename T>
    static void register_server_map() {
        get_server_map<T>();
    }

    static void register_data_map() {
        get_messager_map();
    }

    template<typename T>
    static void register_data_map() {
        get_messager_map<T>();
    }

    template<typename T0, typename T1>
    static void register_data_map() {
        get_messager_map<T0, T1>();
    }

    template<typename T0, typename T1, typename T2>
    static void register_data_map() {
        get_messager_map<T0, T1, T2>();
    }

    template<typename T0, typename T1, typename T2, typename T3>
    static void register_data_map() {
        get_messager_map<T0, T1, T2, T3>();
    }

    template<typename T0, typename T1, typename T2, typename T3, typename T4>
    static void register_data_map() {
        get_messager_map<T0, T1, T2, T3, T4>();
    }

    template<typename T>
    static std::vector<std::string> get_server_list() {
        std::vector<std::string> keys;
        auto& server_map = get_server_map<T>();
        for (auto& server : server_map){
            if (server.second){
                keys.push_back(server.first);
            }
        }
        return keys;
    }

private:
    template<typename T>
    static std::unordered_map<std::string, std::function<T>> &get_server_map() {
        static std::unordered_map<std::string, std::function<T>> server_func_map;
        return server_func_map;
    }

    static std::unordered_map<std::string, std::vector<std::function<void()>>> &get_messager_map() {
        static std::unordered_map<std::string, std::vector<std::function<void()>>> messager_map;
        return messager_map;
    }

    template<typename T>
    static std::unordered_map<std::string, std::vector<std::function<void(const T &)>>> &get_messager_map() {
        static std::unordered_map<std::string, std::vector<std::function<void(const T &)>>> messager_map;
        return messager_map;
    }

    template<typename T0, typename T1>
    static std::unordered_map<std::string, std::vector<std::function<void(const T0 &, const T1 &)>>> &get_messager_map() {
        static std::unordered_map<std::string, std::vector<std::function<void(const T0 &, const T1 &)>>> messager_map;
        return messager_map;
    }

    template<typename T0, typename T1, typename T2>
    static std::unordered_map<std::string, std::vector<std::function<void(const T0 &, const T1 &, const T2 &)>>> &
    get_messager_map() {
        static std::unordered_map<std::string, std::vector<std::function<void(const T0 &, const T1 &, const T2 &)>>> messager_map;
        return messager_map;
    }

    template<typename T0, typename T1, typename T2, typename T3>
    static std::unordered_map<std::string, std::vector<std::function<void(const T0 &, const T1 &, const T2 &, const T3 &)>>> &
    get_messager_map() {
        static std::unordered_map<std::string, std::vector<std::function<void(const T0 &, const T1 &, const T2 &,
                                                                    const T3 &)>>> messager_map;
        return messager_map;
    }

    template<typename T0, typename T1, typename T2, typename T3, typename T4>
    static std::unordered_map<std::string, std::vector<std::function<void(const T0 &, const T1 &, const T2 &, const T3 &,
                                                                const T4 &)>>> &
    get_messager_map() {
        static std::unordered_map<std::string, std::vector<std::function<void(const T0 &, const T1 &, const T2 &, const T3 &,
                                                                    const T4 &)>>> messager_map;
        return messager_map;
    }
};


#endif

test_messager.cpp 

#include <iostream>
#include <string>
#include <memory>

#include "messager.hpp"

using namespace std;

#define MESSAGE_SHOW_RESULR         "show_result"
#define MESSAGE_ADD_INT_NUMBER      "add_number"

struct TData {
    std::string str;
    int   iCount;
    double dPercent;
};

// 消息处理者1
class DataDealerOne {
public:
    static DataDealerOne *GetInstance() {
        static DataDealerOne s_instande;
        return &s_instande;
    }
    virtual ~DataDealerOne() {}
    void subcribeMessage() {
        SelfMessager::subcribe<TData>(
            MESSAGE_SHOW_RESULR, 
            [this](const TData &data) {
            auto data_info = std::make_shared<TData>();
            *data_info = data;
            std::cout << data_info->str << " "
                      << data_info->iCount << " "
                      << data_info->dPercent << std::endl;
        });
    }

private:
    DataDealerOne() {
    }
};

// 消息处理者2
class DataDealerTwo {
public:
    static DataDealerTwo *GetInstance() {
        static DataDealerTwo s_instande;
        return &s_instande;
    }
    virtual ~DataDealerTwo() {}
    void subcribeMessage() {
        SelfMessager::subcribe<int, int>(
            MESSAGE_ADD_INT_NUMBER, 
            [this](const int &a, const int &b) {
                int result = a + b;
                std::cout << a << " + " << b << " = " << result<< std::endl;
        });
    }

private:
    DataDealerTwo() {
    }
};

class Invoker {
public:
    static Invoker *GetInstance() {
        static Invoker s_instande;
        return &s_instande;
    }

    void CallOther(const std::string& message) {
        if (message == MESSAGE_SHOW_RESULR) {
            //发布消息1
            TData data = {"hello world !", 110, 1.234};
            SelfMessager::publish(MESSAGE_SHOW_RESULR, data);
        }
        else if (message == MESSAGE_ADD_INT_NUMBER) {
            //发布消息2
            int num = 0;
            SelfMessager::publish(MESSAGE_ADD_INT_NUMBER, 111, 222);
            std::cout << num << std::endl;
        }
    }

private:
    Invoker() {}
};

int main(int argc, char* argv[]) {
    //订阅消息
    DataDealerOne::GetInstance()->subcribeMessage();
    DataDealerTwo::GetInstance()->subcribeMessage();

    //调用
    Invoker::GetInstance()->CallOther(MESSAGE_SHOW_RESULR);
    Invoker::GetInstance()->CallOther(MESSAGE_ADD_INT_NUMBER);

    return 0;
}

运行效果如下:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/101649.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【LeetCode题目详解】(四)20.有效的括号、225.用队列实现栈

目录 一、力扣第20题&#xff1a;有效的括号 1.解题思路 2.写出代码 3.完整代码 二、力扣第225题&#xff1a;用队列实现栈 1.思路分析 2.代码实现 3.完整代码 总结 一、力扣第20题&#xff1a;有效的括号 题目链接&#xff1a;20. 有效的括号 - 力扣&#xff08;Leetc…

计算机毕设Python+Vue学生寝室管理系统(程序+LW+部署)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

哈夫曼树的构造及应用

哈夫曼树的构造及应用 文章目录哈夫曼树的构造及应用带权路径长度哈夫曼树定义哈夫曼树的性质&#xff1a;构造哈夫曼树构造哈夫曼树存储及生成算法算法框架代码实操:应用: 哈夫曼编码带权路径长度 设二叉树具有n个带权值的叶子节点,那么从根节点到各个叶子节点的路径长度与相应…

【图像分割】模糊聚类算法FCM图像分割【含Matlab源码 084期】

⛄一、模糊聚类算法FCM简介 1 前言 图像分割是图像进行后续分析处理的基础&#xff0c;它将图像分成不同特征部分并获得所需目标&#xff0c;广泛应用于诸多领域&#xff0e;彩色多目标图像具有更为丰富的图像信息&#xff0c;目标色彩较多&#xff0c;且同一色彩的目标有时具…

统计学习方法 | 感知机

感知机是二类分类的线性分类模型&#xff0c;其输入为实例的特征向量&#xff0c;输出为实例的类别&#xff0c;取1和-1二值 感知机对应于输入空间&#xff08;特征空间&#xff09;中将实例划分为正负两类的分离超平面&#xff0c;属于判别模型 一.模型介绍和学习策略 1.模…

牛客题霸sql入门篇之多表查询

牛客题霸sql入门篇之多表查询 1 子查询 1.1 浙江大学用户题目回答情况 1.1.1 题目内容 a 内容1 b 内容2 1.1.2 示例代码 SELECT device_id,question_id,result FROM question_practice_detail WHERE device_id(SELECT device_id FROM user_profile WHERE university浙江大…

[附源码]计算机毕业设计Python的个人理财系统(程序+源码+LW文档)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

pyqt 搭建深度学习训练界面(二)

炼丹软件 github链接: 有需要联系我 requirements: 测试在ubuntu18.04和Windows均可运行 ubuntu18.04 OS: Ubuntu 18.04.6 LTS Python version: 3.7 (64-bit runtime) Is CUDA available: True CUDA runtime version: 11.1.74 GPU models and configuration: GPU 0: NVI…

基于云的文档管理软件/文档管理系统(DMS)

基于云的文档管理软件 由于违反法规而导致的安全漏洞、数据丢失、版本管理等难题和诉讼已经变得非常普遍&#xff0c;以至于这一切都感觉像是“正常”的现象。使用文档管理系统&#xff0c;可以让您避免这些麻烦。安全标准的执行、信息的合规性和维护都在控制之中&#xff0c;只…

【人脸识别】SVM和PCA人脸识别【含GUI Matlab源码 369期】

⛄一、简介 1 PCA-SVM原理 1.1 主成分分析PCA 本文处理的所有原始图片都是112x 92大小的pgm格式图片&#xff0c; 每幅图片包含10304个像素点&#xff0c; 每一行代表一个样本&#xff0c;维数就是10304维。维数过大使得数据处理工作十分复杂&#xff0c;同时&#xff0c;图片…

axios传参的语法

请求方式 POST 向服务器新增数据 GET 从服务器获取数据 DELETE 删除服务器上的数据 PUT 更新服务器上的数据(侧重于完整更新:例如更新用户的完整信息) PATCH 更新服务器上的数据(侧重于部分更新:例如只更新用户的手机号 ) get axios({url: 请求地址,m…

制作自已的屏保动态

制作自已的屏保动态我的环境第一步&#xff1a;编写自己的屏保程序1、代码准备2、编译第二步&#xff1a;有了可运行程序&#xff0c;使用RAR压缩工具将资源和程序打包成独立可执行exe第三步&#xff1a;将dist.exe配置成系统屏幕保护参考我的环境 win10 python3.X pycharm 第…

Linux学习08-认识与学习BASH

1 认识BASH 我们必须要通过Shell将我们输入的命令与内核沟通&#xff0c;好让内核可以控制硬件来正确无误地工作。 Bash shell的功能 历史命令&#xff1a;命令行按“上下键”就可以找到前/后一个输入的指令。 命令与文件补全功能&#xff1a; [Tab] 接在一串指令的第一个…

大学生学习网站哪里找?收好这15个网站

1.学堂在线 地址:https://www.xuetangx.com/ 这里面的课程都是精选&#xff0c;以北大清华为首的高校汇聚于此 2.中国大学生MOOC 地址:https://www.icourse163.org/ 不多说都是精品 3.网易公开课 地址:https://open.163.com/ 网易公开课汇集清华、北大、哈佛、耶鲁等世界名…

全景分割~

Hinton组提出基于大型全景掩码的实例分割框架&#xff0c;图像视频场景丝滑切换 全景分割是一项基本的视觉任务&#xff0c;该任务旨在为图像的每个像素指定语义标签和实例标签。语义标签描述每个像素的类别&#xff08;例如天空、竖直物体等&#xff09;&#xff0c;实例标签…

408 | 考前知识拾遗

计网 二、物理层 各种编码图像 数据交换方式——怎么算时间 VLAN每个VLAN都是一个广播域 三、数据链路层 差错控制&#xff1a;检错、纠错 停等、GBN、SR差别 随机访问 VLAN的考点 交换机&#xff1a;转发、自学习 四、网错层 路由协议/算法 ☆☆☆IPV4分组 1、网关配置、路由…

JVM——常量池

目录一、常量池二、运行时常量池三、intern方法 1.8四、intern方法 1.6五、StringTable 垃圾回收六、StringTable调优通过解决以下问题可以更深入了解字符串创建过程中的原理 一、常量池 二进制字节码的组成&#xff1a;类的基本信息、常量池、类的方法定义&#xff08;包含…

集合的框架体系和Collection接口

1.集合的理解和好处 前面我们保存多个数据使用的是数组&#xff0c;那么数组有不足的地方&#xff0c;我们分析一下 1.1数组 1)长度开始时必须指定&#xff0c;而且一旦指定&#xff0c;不能更改 2)保存的必须为同一类型的元素 3)使用数组进行增加/删除元素的示例代码-比较麻烦…

调试3D渲染和3D可视化的五个好处

建筑和建筑环境是我们日常生活中不可避免的一部分&#xff0c;直接影响我们和我们的福祉。它可以是我们的家、办公室、附近的教堂或城市的商业综合体;所有这一切的设计和规划都是建筑。然而&#xff0c;具有讽刺意味的是&#xff0c;建筑的交流往往并不具有包容性。例如&#x…

玩以太坊链上项目的必备技能(函数及其可见性和状态可变性-Solidity之旅十三)

状态变量可见性 在这之前的文章里&#xff0c;给出的例子中&#xff0c;声明的状态变量都修饰为public&#xff0c;因为我们将状态变量声明为public后&#xff0c;Solidity 编译器自动会为我们生成一个与状态变量同名的、且函数可见性为public的函数&#xff01; 在 Solidity…