C++ 11標準簡單實現觀察者模式
阿新 • • 發佈:2018-12-14
觀察者模式簡單理解:被觀察者的狀態發生變化,觀察者的行為同時也發生變化。
觀察者模式的簡單應用:
1.宣告被觀察者物件。
2.觀察者向被觀察者註冊訊息相應函式。
3.觀察者屬性發生變化,同時註冊上的觀察者出發響應。
上面就是我對觀察者的簡單的理解,但是實際上並不只是如此。 目前有很多開源庫都實現了這樣的模式。譬如Qt中的connect函式,boost庫中的signals2模組等等。有興趣的朋友可以看看他們的原始碼。我這裡只是一個簡單的實現,沒有非常強大的功能。
以下是我寫的程式碼, 在vs2017上面是驗證沒有問題的。
#ifndef __DELEGATE_H__ #define __DELEGATE_H__ #include <iostream> #include <list> #include <functional> #include <algorithm> template <typename> class delegate{}; template <typename R,typename ...Args> class delegate<R(Args...)>{ typedef std::function<R(Args...)> delegate_func; typedef std::list<delegate_func> func_list; public: delegate(); delegate(const unsigned int& count); ~delegate(); bool empty() const; bool full() const; unsigned int size() const; void resize(const int& size); unsigned int max_size() const; bool connect( delegate_func& func); template<typename C> bool connect(R(C::*func)(Args...),C* c_ptr); template<typename C> bool connect(C& mem); bool disconnect(delegate_func func); template<typename C> bool disconnect(R(C::*func)(Args...),C* c_ptr); template<typename C> bool disconnect(C& mem); bool disconnect_all(); void emit(Args&& ...args) const; private: func_list _list; unsigned int _max_count; }; template <typename R,typename ...Args> delegate<R(Args...)>::delegate() :_max_count(0) { } template <typename R,typename ...Args> delegate<R(Args...)>::delegate(const unsigned int& count) :_max_count(count) { } template <typename R,typename ...Args> delegate<R(Args...)>::~delegate() { _max_count = 0; _list.clear(); } template<typename R,typename ...Args> bool delegate<R(Args...)>::empty() const { return _list.empty(); } template<typename R,typename ...Args> unsigned int delegate<R(Args...)>::size() const { return _list.size(); } template<typename R,typename ...Args> bool delegate<R(Args...)>::full() const { return size() >= max_size() ? true : false; } template<typename R,typename ...Args> void delegate<R(Args...)>::resize(const int& size) { this._max_count = size; } template<typename R,typename ...Args> unsigned int delegate<R(Args...)>::max_size() const { return _max_count; } template <typename R,typename ...Args> bool delegate<R(Args...)>::connect(delegate_func& func) { bool ret = false; if(!full) { _list.push_back(func); ret = true; } return ret; } template <typename R,typename ...Args> template<typename C> bool delegate<R(Args...)>::connect(R(C::*func)(Args...), C* c_ptr) { bool ret = false; if(!full()) { _list.push_back(std::bind(func,c_ptr,std::placeholders::_1)); ret = true; } return ret; } template <typename R,typename ...Args> template<typename C> bool delegate<R(Args...)>::connect(C& mem) { bool ret = false; delegate_func func = mem; if(!full()) { _list.push_back(func); ret = true; } return ret; } template <typename R,typename ...Args> bool delegate<R(Args...)>::disconnect(delegate_func func) { bool ret = false; auto itor = std::find_if(_list.begin(), _list.end(), [&](delegate_func& f) -> bool { delegate_func &fn = func; if (f && f.target<R(*)(Args...)>() == fn.target<R(*)(Args...)>()) { return true; } return false; }); if (itor != _list.end()) { _list.erase(itor); ret = true; } return ret; } template <typename R,typename ...Args> template<typename C> bool delegate<R(Args...)>::disconnect(R(C::*func)(Args...),C* c_ptr) { bool ret = false; auto itor = std::find_if(_list.begin(),_list.end(),[&](delegate_func& f)->bool{ delegate_func fc = std::bind(func,c_ptr); if(f && f.target<R(*)(Args...)>() == fc.target<R(*)(Args...)>()) { return true; } return false; }); if(itor != _list.end()) { _list.erase(itor); ret = true; } return ret; } template <typename R,typename ...Args> template<typename C> bool delegate<R(Args...)>::disconnect(C& mem) { bool ret = false; auto itor = std::find_if(_list.begin(), _list.end(), [&](delegate_func& f) -> bool { delegate_func &fn = mem; if (f && f.target<R(*)(Args...)>() == fn.target<R(*)(Args...)>()) { return true; } return false; }); if (itor != _list.end()) { _list.erase(itor); ret = true; } return ret; } template<typename R,typename ...Args> bool delegate<R(Args...)>::disconnect_all() { bool ret = false; _list.clear(); if(empty()) { ret = true; } return ret; } template<typename R,typename ...Args> void delegate<R(Args...)>::emit(Args&& ...args) const { for(auto func : _list) { try{ func(args...); } catch(std::exception& ex) { std::cout << ex.what() << std::endl; } } } #endif //__DELEGATE_H__
注意:在我寫這段程式碼的時候,由於沒有考慮的特別清楚,使用了std::list容器當作了觀察者函式的載體。所以,在disconnect的時候我是使用std::function中的target來判斷兩個std::function物件是否相等。但是,從網上查了下資料。這樣的判斷並不完美,會存在錯誤。 所以,如果有想使用這塊程式碼的同學們,可以使用std::unordered_map 容器來替代list容器。這裡可能會有同學問我為什麼不使用map容器,哈哈。雖然扯的有點遠,但是我想說的是map容器會實現自動排序。這個功能我們並不需要。為了節約那麼一丟丟的效能。(其實這裡我想說的是寫程式碼的時候要選擇合適的)。
最後,我就不貼測試程式碼了, 有興趣的可以自己寫一寫。