C++11之用std::function和std::bind实现观察者模式
使用C++11中的std::bind和std::function以及模板可以很好的实现观察者模式,现在把自己的一些实现的想法记录在此.
编译环境:VS2017
实现的想法:将各个类之间进行解耦,使用C++11的特性实现观察者,C++11中的std::function中可以传函数和lambda仿函数,感觉类似标准之前的回调函数,有时间会去剖析一下该特性.
观察者模式简介:
主体类中维护一个观察者的列表,如果有消息传过来,列表将把所有的消息遍历一遍,一般列表元素是一个父类指针,利用继承的特性实现子类中的相应.
类似于此:
class Subject { public: std::vector<Base*>m_vec; };
利用模板的静态多态去取代继承的动态多态.
如此实现的话会造成各个模块之间的耦合过强,对子类的修改也会影响到父类。
更改的代码如下:
1 使用std::function在调用之前完成对列表元素的添加(可以称之为注册)
2 利用模板实现类型的推导
3 使用std::map来存储数据,用于当作主体中的观察者列表
code 如下:
1 #include "pch.h" 2 #include <iostream> 3 #include <vector> 4 #include <functional> 5 #include <map> 6 7 template<typename EVENT> 8 class Subject 9 { 10 public: 11 template<typename OBSERVER> 12 void registerObser(const EVENT&event, OBSERVER&&observer) 13 { 14 m_map_observers[event].push_back(std::forward<OBSERVER>(observer)); 15 } 16 17 void notify(const EVENT&event)const 18 { 19 for (auto &itor : m_map_observers.at(event)) 20 { 21 itor(); 22 } 23 } 24 25 private: 26 std::map<EVENT, std::vector<std::function<void()>>> m_map_observers; 27 }; 28 29 30 class Derive1 31 { 32 public: 33 34 void printMsg() { std::cout << __func__ << std::endl; } 35 }; 36 37 class Derive2 38 { 39 public: 40 void printMsg(int level) { std::cout << __func__ << "level is " << level << std::endl; } 41 }; 42 43 class VarDef 44 { 45 public: 46 VarDef(std::string s1) :m_s1(s1) {} 47 VarDef(std::string s1, int level) :m_s1(s1), m_level(level) {} 48 std::string m_s1; 49 int m_level; 50 friend bool operator<(const VarDef&left, const VarDef&right) 51 { 52 if (left.m_s1 == right.m_s1) 53 return (left.m_level < right.m_level); 54 else 55 return (left.m_s1 < right.m_s1); 56 } 57 }; 58 59 int main() 60 { 61 Subject<VarDef> s; 62 63 s.registerObser(VarDef("Derive1"), std::bind(&Derive1::printMsg, &Derive1())); 64 s.registerObser(VarDef("Derive2", 2), std::bind(&Derive2::printMsg, &Derive2(),2)); 65 66 s.notify(VarDef("Derive2",2)); 67 68 return 0; 69 }
实现功能:
维护类VarDef来实现针对不同Message的打印.在该类中需要定义多个构造函数来完成不同的功能.
对外暴露的接口为registerObser,notify,在使用之前需要对多份消息进行注册,当有消息过来时便可以进行通知.