Application development process often deal with inter-object communication problems, generally is the object or interface dependencies and references to achieve communication between objects, which in general is not a problem, but if the object of communication with a lot of objects may cause the reference relationship between the object like a spider web, which will lead to complex object relations, Difficult to maintain, a good way to solve this problem is to decouple the tightly coupled relationships between objects through a message bus.
Design idea: The communication object publishes a topic to the message bus, which contains the message subject, message type, and message handler, the message topic identifies a particular topic, and the message type is used to distinguish the subject from a particular message, and the message handler is used to respond to the message type of the subject. When a communication object sends a specific primary and a specific message to the message bus, the bus will find the corresponding message handler based on the message subject and message type to process the request.
Due to the use of c++11 variable template parameters and Lamda expressions, compiling on Windows requires compiler Ctp,linux need GCC4.7 above.
Specific code:
#pragmaOnce#include<boost/tuple/tuple.hpp>#include<boost/utility.hpp>#include<boost/unordered_map.hpp>#include<boost/any.hpp>Template<typename ... Args>structimpl;template<typename First, TypeName ... Args>structImpl<first, args...>{ StaticSTD::stringname () {returnSTD::string(typeID (first). Name ()) +" "+ impl<args...>:: Name (); }};template<>structImpl<>{ StaticSTD::stringname () {return ""; }};template<typename ... Args>std::stringtype_name () {returnImpl<args...>:: Name ();}classmessagebus:boost::noncopyable{ Public: //to register a topic with a topic, you need to subscribe to topics (topic, message Types), and message handler functions. Template<typename ... Targs, TypeName TObject, TypeName tmember>voidAttach (stringStrtopic, 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)); } //sending a message to a topic requires a subject and message type. When the message bus receives the message, it finds and notifies the corresponding message handler function. Template<typename ... Args>voidSendreq (stringstrtopic, 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, subject and message type requiredTemplate<typename ... Args>voidRemove (stringstrtopic) {Auto It=M_map.find (GetKey (strtopic)); while(it!=m_map.end ()) M_map.erase (It++); }Private: //gets the message key value, which can be determined by a topic and message typeTemplate<typename ... Targs>stringGetKey (string&strtopic) { returnStrtopic + 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);//Registering the subject (topic, message type, message handler function)Bus. attach<int,string> ("BB", &st, &mystruct::test2); Bus. Sendreq<int,string> ("BB",0,"Append");//Send Message processing requests (subject 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
Updated version, through the Universal function wrapper to implement the message bus, making the interface calls more general and consistent.
Template <typename r=void>classmessagebus:boost::noncopyable{ Public: //Register Messagetemplate<class... Args,classFclass= TypeName Std::enable_if<!std::is_member_function_pointer<f>::value>::type>voidAttach (stringStrkey, F &&f) {std::function<r (Args ...) > fn = [&] (args ... args) {returnF (std::forward<args>(args) ...); }; M_map.insert (Std::make_pair (strkey+ Type_name < args...>(), Std::move (FN))); } //Non-const member functiontemplate<class... Args,classCclass... Dargs,classP>voidAttach (stringStrkey, 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,classCclass... Dargs,classP>voidAttach (stringStrkey, 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 messages, topics, and parameters can determine a message, and all message recipients will receive and process the messageTemplate<typename ... Args>voidSendreq (stringstrtopic, 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 ...); } } //removing messages fromTemplate<typename ... Args>voidRemove (stringstrtopic) { stringStrmsgtype = 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:
structa{voidTest (intx) {cout << x <<Endl;} voidgtest () {cout<<"It is a test"<<Endl; } voidHtest (intXConst{cout<<"It is a htest"<<Endl; }};voidGG (intx) {cout<<"It is a GG"<<Endl;}voidGG1 () {cout<<"It is a GG"<<Endl;}voidTestmessagebus () {a A; Messagebus<>bus; Bus. Attach<int> ("AA", &a::test, &a); intx =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");}
A common C + + message bus framework