使用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,在使用之前需要對多份消息進行注冊,當有消息過來時便可以進行通知.
