一、什么是消息总线
在大规模的软件开发过程中,对象很多,关联关系非常复杂,如果没有统一的、简洁的方法去管理这些对象关系,会导致对象之间交互困难,后期难以维护。
基于消息总线技术可以解决这些问题。在消息总线中,对象是通过消息来联系,消息即是对象的关系。只需要在消息总线中管理这些消息,不用关心具体哪些对象之间有关联,便于统一管理。
二、消息总线包含的内容
2.1 消息定义
定义一种通用的消息格式,让所有的对象都能接收。
通用的消息类型的定义:主题+泛型函数的签名。主题用来将消息的接收者进行分组,只有某个特定组的接收者才能收到消息。泛型函数用来确定哪些接收者具备接收该消息的能力。
这里主题用string类型来表示,
泛型函数可能是所有的可调用对象,例如:普通函数,成员函数,函数对象,std::function和lamda表达式。要统一这些接口,就是将这些全部转换为std::function。
std::function<R(Args…)>
std::function作为消息类型
R 函数返回类型
Args… 是一个可变参数模板,代表了任意个数类型的参数
2.2 消息的注册
某个对象注册以后,当需要使用的时候,会告诉总线,总线就会遍历该消息列表容器,查找对应的消息和消息的接收者,找到以后再广播消息。
消息类型:topic + std::function<R(Args...)>。
对于不同的Args和R,消息类型是不同的。为了保存不同的消息对象,需要用Any做类型擦除。
最后,消息总线内部使用multimap来保存消息,键为topic + typeid的字符串,值为消息对象。
std::multimap<string,Any> m_map;
消息注册如下:
// 注册可调用对象
template<typename T>
void Attach(const string& strTopic, const F& f)
{
auto func = to_function(std::forward<F>(f));
Add(strTopic, std::move(func));
}
template<typename T>
void Add(const string& strTopic, F&& f)
{
// typeid 运算符用来获取一个表达式的类型信息
string strKey = strTopic + typeid(F).name();
// Any类型擦除
m_map.emplace(std::move(strMsgType), std::forward<F>(f));
}
2.3 消息的分发
消息总线通过主题发送消息。会查找消息总线内部的容器,找到对这个消息感兴趣的对象,并一一调用,即一一发送消息。
template<typename R, typename... Args>
void sendReq(Args&&... args, const string& strTopic = "")
{
using function_type = std::function<R(Args...)>;
string strMsgType = strTopic + typeid(function_type).name();
auto range = m_map.equal_range(strMsgType);
for (Iterator it = range.first(); it != range.second; it++)
{
auto f = it->second.AnyCast<function_type>();
f(std::forward<Args>(args)...);
}
}
三、消息总线的实现
设计思路
融合了观察者模式和中介者模式,通过Any类擦除了消息的类型,使得消息总线可以管理所有类型的消息。观察者模式用来维护主题和在适当的时候向观察者广播消息;中介者模式主要用来降低观察者模式相互依赖产生的耦合性,使各对象不需要显式地相互引用,而且可以独立地改变它们之间的交互关系。
NonCopyable类 :防止类的拷贝,需要这个功能的都可以继承它
MessageBus类: 消息总线
Any类:存储任何对象的容器
function_traits:获取普通函数、函数指针、std::function、函数对象以及成员函数的函数类型、返回类型、参数个数和参数的具体类型
文件目录结构如下
NonCopyable.h
/*
* THIS CLASS CAN DEFINE A CALSS WHICH NOT SUPPORT COPY CONSTRUTOR
* AND COPY OPERATOR FUNCTION
*/
class NonCopyable
{
protected:
NonCopyable() = default;
~NonCopyable() = default;
NonCopyable(const NonCopyable&) = delete;
NonCopyable& operator=(const NonCopyable&) = delete;
};
Any.h
#include <memory>
#include <iostream>
#include <typeindex>
struct Any
{
Any(void) : m_tpIndex(std::type_index(typeid(void))) {}
//复制拷贝构造函数
Any(Any &that) : m_ptr(that.Clone()), m_tpIndex(that.m_tpIndex) {}
Any(const Any &that) : m_ptr(that.Clone()), m_tpIndex(that.m_tpIndex) {}
Any(Any &&that) : m_ptr(std::move(that.m_ptr)), m_tpIndex(that.m_tpIndex) {}
//std::enable_if 条件判断,只有当条件满足时,才有效,否则编译报错
//std::is_same 判断两个类型是否相同
//std::decay 擦除类型的修饰,退化为基本形态
template <typename U, class =
typename std::enable_if<!std::is_same<typename std::decay<U>::type, Any>::value, U>::type>
Any(U &&value) : m_ptr(new Derived<typename std::decay<U>::type>(std::forward<U>(value))),
m_tpIndex(std::type_index(typeid(typename std::decay<U>::type))) {}
bool IsNULL() const { return !bool(m_ptr); }
template <class U>
bool Is() const // //判断给定的类型与存储的数据类型是否相同
{
return m_tpIndex == std::type_index(typeid(U));
}
template <class U>
U &AnyCast()
{
if (!Is<U>())
{
std::cout << "can not cast " << typeid(U).name() << " to " << m_tpIndex.name() << std::endl;
}
auto derived = dynamic_cast<Derived<U> *>(m_ptr.get());
return derived->m_value;
}
Any &operator=(const Any &a)
{
if (m_ptr == a.m_ptr)
return *this;
m_ptr = a.Clone();
m_tpIndex = a.m_tpIndex;
return *this;
}
private:
struct Base; // 存放原始数据的基类
typedef std::unique_ptr<Base> BasePtr;
struct Base
{
virtual ~Base() {}
virtual BasePtr Clone() const = 0;
};
template <typename T>
struct Derived : Base
{
template <typename U>
Derived(U &&value) : m_value(std::forward<U>(value)) {}
BasePtr Clone() const
{
return BasePtr(new Derived<T>(m_value));
}
T m_value;
};
public:
BasePtr Clone() const
{
if (m_ptr != nullptr)
return m_ptr->Clone();
return nullptr;
}
BasePtr m_ptr;
std::type_index m_tpIndex;
};
function_traits.h
#include <functional>
#include <tuple>
//转换为std::function和函数指针.
template<typename T>
struct function_traits;
// 普通函数
template<typename Ret, typename... Args>
struct function_traits<Ret(Args...)>
{
public:
enum {arity = sizeof...(Args)};
typedef Ret function_type(Args...);
typedef Ret return_type;
using stl_function_type = std::function<function_type>; // 自定义函数类型
typedef Ret(*pointer)(Args...);
template<size_t I>
struct args
{
static_assert(I < arity, "index is out of range, index must less than sizeof Args");
using type = typename std::tuple_element<I, std::tuple<Args...>>::type;
};
};
// 函数指针
template<typename Ret, typename... Args>
struct function_traits<Ret(*)(Args...)> : function_traits<Ret(Args...)> {};
//std::function
template<typename Ret, typename... Args>
struct function_traits<std::function<Ret(Args...)>> : function_traits<Ret(Args...)>{};
// 成员函数
#define FUNCTION_TRAITS(...) \
template<typename ReturnType, typename ClassType, typename... Args>\
struct function_traits<ReturnType(ClassType::*)(Args...) __VA_ARGS__> : \
function_traits<ReturnType(Args...)>{};
FUNCTION_TRAITS();
FUNCTION_TRAITS(const);
FUNCTION_TRAITS(volatile);
FUNCTION_TRAITS(const volatile);
// 函数对象
template<typename Callable>
struct function_traits : function_traits<decltype(&Callable::operator())>{};
// 左值引用的lamda表达式
template<typename Function>
struct function_traits<Function>::stl_function_type to_function(const Function &lambda)
{
return static_cast<typename function_traits<Function>::stl_function_type>(lambda);
}
// 右值引用的lamda表达式
template<typename Function>
struct function_traits<Function>::stl_function_type to_function(Function && lambda)
{
return static_cast<typename function_traits<Function>::stl_function_type>(std::forward<Function>(lambda));
}
// 指针对象
template<typename Function>
struct function_traits<Function>::pointer to_function_pointer(const Function &lambda)
{
return static_cast<typename function_traits<Function>::pointer>(lambda);
}
MessageBus.h
#include <string>
#include <functional>
#include <map>
#include "Any.h"
#include "function_traits.h"
#include "NonCopyable.h"
using namespace std;
class MessageBus : NonCopyable
{
public:
///注册消息
template<typename F>
void Attach(F && f, const string& strTopic="")
{
auto func = to_function(std::forward<F>(f));
Add(strTopic, std::move(func));
}
//发送消息
template<typename R>
void SendReq(const string &strTopic="")
{
using function_type = std::function<R()>;
string strMsgType = strTopic + typeid(function_type).name();
auto range = m_map.equal_range(strMsgType); //range std::pair<iterator, iterator>
//std::pair<std::multimap<string, Any>::iterator, std::multimap<string, Any>::iterator> range = m_map.equal_range(strMsgType);
for(Iterater it=range.first; it!=range.second; ++it)
{
auto f = it->second.AnyCast<function_type>();
f();
}
}
template<typename R, typename... Args>
void SendReq(Args&&... args, const string& strTopic="")
{
// std::function 函数对象类,包装了满足该函数模板类型的任意函数对象,
// 这些目标实体包括普通函数、Lambda表达式、函数指针、模函数、类成员函数、
// 类静态函数以及其它的函数对象
using function_type = std::function<R(Args...)>;
string strMsgType = strTopic + typeid(function_type).name();
auto range = m_map.equal_range(strMsgType);
for(Iterater it=range.first; it!=range.second; ++it)
{
auto f = it->second.AnyCast<function_type>();
f(std::forward<Args>(args)...);
}
}
// 移除某个主题,需要主题和消息类型
template<typename R, typename... Args>
void Remove(const string& strTopic="")
{
using function_type = std::function<R(Args...)>;
string strMsgType = strTopic + typeid(function_type).name();
int count = m_map.count(strMsgType);
auto range = m_map.equal_range(strMsgType);
m_map.erase(range.first, range.second);
}
private:
template<typename F>
void Add(const string& strTopic, F && f)
{
string strMsgType = strTopic + typeid(F).name();
m_map.emplace(std::move(strMsgType), std::forward<F>(f));
}
private:
std::multimap<string, Any> m_map;
typedef std::multimap<std::string, Any>::iterator Iterater;
};
test.cpp
#include "MessageBus.h"
#include <iostream>
MessageBus g_bus; // 全局的消息总线
const string Topic = "Drive"; // 主题
const string CallBackTopic = "DriveOK"; //执行结果返回主题
struct Subject
{
Subject()
{
g_bus.Attach([this] { DriveOk(); }, CallBackTopic);
}
void SendReq(const string &topic)
{
g_bus.SendReq<void, int>(50, topic);
}
void DriveOk()
{
std::cout << "DriveOk" << std::endl;
}
};
struct Car
{
Car()
{
g_bus.Attach([this](int speed){Drive(speed);}, Topic);
}
void Drive(int speed)
{
std::cout << "Car Drive.." << std::endl;
g_bus.SendReq<void>(CallBackTopic);
}
};
struct Bus
{
Bus()
{
g_bus.Attach([this](int speed){Drive(speed);}, Topic);
}
void Drive(int speed)
{
std::cout << "Bus Drive..." << std::endl;
g_bus.SendReq<void>(CallBackTopic);
}
};
struct Truck
{
Truck()
{
g_bus.Attach([this](int speed){Drive(speed);});
}
void Drive(int speed)
{
std::cout << "Truck Drive.." << std::endl;
g_bus.SendReq<void>(CallBackTopic);
}
};
int main()
{
Subject subject;
Car car;
Bus bus;
Truck truck;
subject.SendReq(Topic);
std::cout << "*****" << std::endl;
subject.SendReq("");
return 0;
}
编译
g++ test.cpp -o test -std=c++11
g++ TestMessageBus.cpp -o TestMessageBus -std=c++11
运行
github链接
https://github.com/hejiajie1989/MessageBus
参考:
c++11实现的一个消息总线框架_hejiajie1989的博客-CSDN博客_c++ 消息总线
[12 使用C++11开发一个对象的消息总线(观察者模式和中介者模式的应用及优化)] 12.2 消息总线关键技术_站在巨人的肩膀上,温故而知新的博客-CSDN博客