admin管理员组

文章数量:1335724

c++11

消息总线

对象间只通过消息来联系,不通过直接的依赖或者关联。消息总线将复杂的关系简化,降低复杂度。

消息总线关键技术

1)通用的消息定义

让所有额对象都通过消息来联系,定义一种通用的消息格式

2)消息的注册

让所有对象都可以注册感兴趣的消息

3)消息分发

通过消息总线分发消息,让所有的接受者都能接收到并处理消息

通用消息的定义

消息的构成=消息的主题+泛型函数

消息主题:用于对消息接受者进行分组,只有对主题感兴趣的接受者,才可以收到消息

泛型函数:用于消息的接收者,所有具备该函数的对象都可以接收消息,std::function<R(Args...)>

消息注册

告诉总线,该对象对某种消息感兴趣,希望接收到某种主题和类型的消息。总线内部维护了一个消息列表,需要发送消息时,遍历这个列表,查找是否有合适的消息和消息接收者,找到合适的接收者后再广播消息。

1.lambda表达式转换为std::function

2.保存注册的消息

消息分发

主题对象希望接收者对象收到消息时,会通过消息总线发送消息,消息的本质是std::function,在发送消息前先创建消息,创建后再发送,消息总线会查找内部的容器,看看那些对象对这个消息感兴趣,只有注册了这个消息的对象才能收到消息。

 

消息总线的设计思想

function_traits:

#pragma once
#include<functional>
#include<tuple>

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");
        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...)>
{

};
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...)>: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())))> {};*/

/*
template<typename Function>
typename function_traits<Function>::stl_function_type to_function(const Function & lambda) {
    return static_cast<typename function_traits<Function>::stl_function_type>(lambda);
}*/

template<typename Function>
typename function_traits<Function>::stl_function_type to_function(Function && la) {
    return static_cast<typename function_traits<Function>::stl_function_type>(std::forward<Function>(la));
}
/*
template<typename Function>
typename function_traits<Function>::pointer to_function(const Function & lambda) {
    return static_cast<typename function_traits<Function>::pointer>((lambda));
}*/

 

messagebus:

#pragma once
#include"function_traits.h"
#include"any.h"
#include<string>
#include<map>

class MessageBus {
public:
    template<typename F>
    void Attach(F&& f, const std::string& strTopic = "") {
        auto func = to_function(std::forward<F>(f));
        Add(strTopic, std::move(func));
    }
    template<typename R>
    void sendReq(const std::string& strTopic = "") {
        using function_type = std::function<R()>;
        std::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();
        }

    }
    template<typename R,typename ... Args>
    void sendReq(Args ... args,const std::string& strTopic = "") {
        using function_type = std::function<R(Args...)>;
        std::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)...);
        }

    }
    template<typename R, typename ... Args>
    void Remove(Args ... args, const std::string& strTopic = "") {
        using function_type = std::function<R(args)>;
        std::string strMsgType = strTopic + typeid(function_type).name();
        auto Range = m_map.equal_range(strMsgType);
        m_map.erase(Range.first,Range.second);
    }
private:
    template<typename F>
    void Add(const std::string& strTopic, F&& f) {
        const std::string strMsgType = strTopic + typeid(f).name();
        std::pair<std::string, Any> p(strMsgType, std::forward<F>(f));
        m_map.insert(std::move(p));
    }
    std::multimap<std::string, Any> m_map;
    typedef std::multimap<std::string, Any>::iterator Iterator;

};

 

 

本文标签: C11