C++利用模板實(shí)現(xiàn)消息訂閱和分發(fā)功能
解耦是編寫程序所遵循的基本原則之一,多態(tài)是提高程序靈活性的重要方法。C++語言支持重載,模板,虛函數(shù)等特性,為編寫高性能可擴(kuò)展的程序提供了利器。編寫大型項(xiàng)目時(shí),免不了需要各個(gè)模塊之間相互調(diào)用,從而產(chǎn)生了模塊之間的耦合。不同模塊之間的關(guān)系稱之為耦合,耦合程度由高到底可以分為以下幾類:
1. 內(nèi)容耦合
內(nèi)容耦合常見情形如下:
1)一個(gè)模塊直接訪問另一個(gè)模塊的內(nèi)容
2)一個(gè)模塊不通過正常入口轉(zhuǎn)到另一個(gè)模塊
3)兩個(gè)模塊有部分程序代碼重疊,常見在匯編語言中
4)一個(gè)模塊有多個(gè)入口
2. 公共耦合
若模塊都訪問同一個(gè)公共數(shù)據(jù)環(huán)境,則稱他們是公共耦合。
3. 外部耦合
模塊通過非參數(shù)傳遞的方式訪問同一個(gè)全局變量,則稱之為外部耦合。C語言中的extern類型變量就是一種外部耦合。
4. 控制耦合
一個(gè)模塊通過傳送參數(shù)和控制信息來選擇控制另一個(gè)模塊的功能,就是控制耦合??刂岂詈献畛R姷姆绞骄褪墙涌谡{(diào)用。
5. 標(biāo)記耦合
6. 數(shù)據(jù)耦合
7. 非直接耦合
訂閱分發(fā)是程序編寫常用的設(shè)計(jì)模式,回調(diào),QT中的信號(hào)槽本質(zhì)都是訂閱模式。兩個(gè)模塊之間可以直接交互,也可以借助第三者來實(shí)現(xiàn)交互。下面將展示一種借助第三者來實(shí)現(xiàn)模塊之間的交互。

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;
}
};
#endiftest_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) {
//發(fā)布消息1
TData data = {"hello world !", 110, 1.234};
SelfMessager::publish(MESSAGE_SHOW_RESULR, data);
}
else if (message == MESSAGE_ADD_INT_NUMBER) {
//發(fā)布消息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();
//調(diào)用
Invoker::GetInstance()->CallOther(MESSAGE_SHOW_RESULR);
Invoker::GetInstance()->CallOther(MESSAGE_ADD_INT_NUMBER);
return 0;
}運(yùn)行效果如下:

到此這篇關(guān)于C++利用模板實(shí)現(xiàn)消息訂閱和分發(fā)功能的文章就介紹到這了,更多相關(guān)C++消息訂閱分發(fā)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于C++的重載運(yùn)算符和重載函數(shù)
一般來說,重載運(yùn)算符在實(shí)際的項(xiàng)目開發(fā)中會(huì)經(jīng)常的用到,但如果某些自定義類型通過簡(jiǎn)短幾行代碼重載一些常用的運(yùn)算符(如:+-*/),就能讓編程工作帶來方便,需要的朋友可以參考下本文2023-05-05
C語言實(shí)現(xiàn)簡(jiǎn)易訂餐系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)簡(jiǎn)易訂餐系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06
數(shù)組中求第K大數(shù)的實(shí)現(xiàn)方法
本篇文章是對(duì)數(shù)組中求第K大數(shù)的實(shí)現(xiàn)方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
C語言實(shí)現(xiàn)簡(jiǎn)易通訊錄實(shí)例
大家好,本篇文章主要講的是C語言實(shí)現(xiàn)簡(jiǎn)易通訊錄實(shí)例,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下2022-02-02
C++處理輸入字符串并轉(zhuǎn)為數(shù)組的操作
這篇文章主要介紹了C++處理輸入字符串并轉(zhuǎn)為數(shù)組的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-01-01
10個(gè)步驟Opencv輕松檢測(cè)出圖片中條形碼
這篇文章主要為大家詳細(xì)介紹了Opencv輕松檢測(cè)出圖片中條形碼的10個(gè)步驟,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01
C語言實(shí)現(xiàn)會(huì)員管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)會(huì)員管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
Cocos2d-x學(xué)習(xí)筆記之Hello World源碼分析
這篇文章主要介紹了Cocos2d-x學(xué)習(xí)筆記之Hello World源碼分析,接上一篇內(nèi)容,本文著重分析源碼文件,需要的朋友可以參考下2014-09-09

