A common C ++ message bus framework and bus framework
In the process of application development, communication between objects is often handled. Generally, communication between objects is implemented through dependency and reference of objects or interfaces, which is normal, however, if there are many objects to communicate with each other, the reference relationships between objects may be the same as those of spider networks, which may cause complicated and difficult to maintain object relationships, A good way to solve this problem is to use the message bus to decouple the tightly coupled relationship between objects referenced by each other.
Design Concept: the communication object publishes a topic to the Message bus. The topic contains the message topic, message type, and message processing function. The message topic indicates a specific topic, the message type is used to differentiate whether a topic will respond to a specific message. The message processing function is used to respond to a certain message type of the topic. When a communication object sends a specific master and a specific message to the Message bus, the bus finds the corresponding message processing function based on the message topic and message type to process the request.
Since the variable template parameters and lamda expressions of c ++ 11 are used, Compiler Nov 2012 CTP is required for compiling on windows, and GCC4.7 or above is required for linux.
Code:
# Pragma once # include <boost/tuple. hpp> # include <boost/utility. hpp> # include <boost/unordered_map.hpp> # include <boost/any. hpp> template <typename... args> struct Impl; template <typename First, typename... args> struct Impl <First, Args...> {static std: string name () {return std: string (typeid (First ). name () + "" + Impl <Args...>: name () ;}}; template <> struct Impl <> {static std: string name () {ret Urn "" ;}}; template <typename... args> std: string type_name () {return Impl <Args...>: name ();} class MessageBus: boost: noncopyable {public: // register a topic with a topic. You need to subscribe to the topic (topic, message type) and message processing function. Template <typename... TArgs, typename TObject, typename TMember> void Attach (string strTopic, TObject * Object, TMember Member) {std: function <void (TArgs...)> f = std: function <void (TArgs...)> ([=] (TArgs... arg) {(Object-> * Member) (arg ...);}); m_map.insert (make_pair (GetKey (strTopic), f);} // send a message to a topic. The topic and message type are required. After receiving the message, the message bus finds and notifies the corresponding message processing function. Template <typename... args> void SendReq (string strTopic, Args... args) {auto range = m_map.equal_range (GetKey (strTopic); boost: unordered_multimap <string, boost: any >:: iterator it; for (it = range. first; it! = Range. second; it ++) {std: function <void (Args...)> f = boost: any_cast <std: function <void (Args...)> (it-> second); f (args ...);}} // remove a topic. The topic and message type template <typename... args> void Remove (string strTopic) {auto it = m_map.find (GetKey (strTopic); while (it! = M_map.end () m_map.erase (it ++);} private: // obtain the Message key value. You can determine the observer template <typename... TArgs> string GetKey (string & strTopic) {return strTopic + type_name <TArgs...> ();} private: boost: unordered_multimap <string, boost: any> m_map ;};
Test code:
MessageBus bus; MyStruct st; bus. attach <int, string> ("bb", & st, & MyStruct: Test); // register the topic (topic, message type, message processing function) bus. attach <int, string> ("bb", & st, & MyStruct: Test2); bus. sendReq <int, string> ("bb", 0, "append"); // send a message processing request (topic and Message Type) bus. remove <int, string> ("bb"); // Remove a topic (subject and message type)
Test results:
It is a test: 0 append
It is a test2: 0 append
The updated version implements the message bus through the universal function wrapper, making interface calls more universal and consistent.
Template <typename R = void> class MessageBus: boost: noncopyable {public: // register the message template <class... args, class F, class = typename std: enable_if <! Std: is_member_function_pointer <F >:: value >:: type> void Attach (string strKey, F & f) {std: function <R (Args...)> fn = [&] (Args... args) {return f (std: forward <Args> (args )...);}; m_map.insert (std: make_pair (strKey + type_name <Args...> (), std: move (fn);} // non-const member function template <class... args, class C, class... DArgs, class P> void Attach (string strKey, R (C: * f) (DArgs ...), P & p ){ Std: function <R (Args...)> fn = [&, f] (Args... args) {return (* p. * f) (std: forward <Args> (args )...);}; m_map.insert (std: make_pair (strKey + type_name <Args...> (), std: move (fn);} template <class... args, class C, class... DArgs, class P> void Attach (string strKey, R (C: * f) (DArgs ...) const, P & p) {std: function <R (Args...)> fn = [&, f] (Args... args) {return (* p. * f) (std: forward <Args> (args )...);}; M_map.insert (std: make_pair (strKey + type_name <Args...> (), std: move (fn);} // broadcast the message. The topic and parameters can determine a message, all message recipients will receive and process the message template <typename... args> void SendReq (string strTopic, Args... args) {auto range = m_map.equal_range (strTopic + type_name <Args...> (); for (auto it = range. first; it! = Range. second; it ++) {std: function <R (Args...)> f = boost: any_cast <std: function <R (Args...)> (it-> second); f (args ...);}} // remove the message template <typename... args> void Remove (string strTopic) {string strMsgType = GetNameofMsgType <Args...> (); auto range = m_map.equal_range (strTopic + strMsgType); m_map.erase (range. first, range. second);} private: std: multimap <string, boost: any> m_map ;};
Test code:
struct A{ void Test(int x){ cout << x << endl; } void GTest() { cout << "it is a test" << endl; } void HTest(int x) const { cout << "it is a HTest" << endl; }};void GG(int x){ cout << "it is a gg" << endl;}void GG1(){ cout << "it is a GG" << endl;}void TestMessageBus(){ A a; MessageBus<> bus; bus.Attach<int>("aa", &A::Test, &a); int x = 3; bus.SendReq("aa", 3); bus.Attach<int>("hh", &A::HTest, &a); bus.SendReq("hh", x); bus.Attach("bb", &A::GTest, &a); bus.SendReq("bb"); bus.Attach<int>("gg", GG); bus.SendReq("gg", 3); bus.Attach("gg", GG1); bus.SendReq("gg");}