C++11通用观察者模式
观察者模式是用来解决观察者和被观察者紧耦合的问题,我们需要实现一个观察者管理类,来避免耦合。但同时引入了新问题。管理类在注册以及移除观察者时,在多线程下是不安全的,所以我们需要用mutex
来保证管理类是线程安全的。
另外观察者管理类只负责广播注册过的观察者,它不对观察者的生命周期负责,如果观察者已经被销毁,管理类还继续调用该观察者的接口,core dump
就是迟早的事情。我们可以用weak_ptr
来探测观察者的生命周期,如果观察者存在那么weak_ptr
就会提升为shared_ptr
,在保证调用安全的同时也不会引起内存泄露,如果直接用shared_ptr
来保存观察者的话,那观察者的生命周期会被延长至管理内销毁为止,这也算一种内存泄露。
再者,我们要想实现一个通用的观察者模式,抽象观察者类的Update
接口必须支持可变参,但问题是变长模板不能用在虚函数上面,这是因为虚函数的调用是基于运行时多态的机制,而模板实例化是在编译期执行的,如果在编译期不能决定调用哪个函数,又怎么能去根据模板参数实例化出不同的函数。但是我们可以用std::vector<std::any>
来模拟变长参数,观察者和被观察者约定一种传参方式,然后观察者根据这种约定来取出参数。而观察者抽象类以及管理类不需要做任何变动。
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 #include <iostream> #include <list> #include <memory> #include <mutex> #include <vector> #include <any> class ManageObserver ;class IObserver {public : virtual ~IObserver () = default ; virtual void Update (std::vector<std::any>) = 0 ; };class ManageObserver {public : ManageObserver () = default ; virtual ~ManageObserver () = default ; ManageObserver (const ManageObserver&) = delete ; ManageObserver (ManageObserver&&) = delete ; ManageObserver& operator =(const ManageObserver&) = delete ; ManageObserver& operator =(ManageObserver&&) = delete ; void RegisterObserver (std::weak_ptr<IObserver>&& observer) { std::lock_guard<std::mutex> lock (m_mutex) ; m_observers.push_back (std::move (observer)); } void RemoveObserver (const std::weak_ptr<IObserver>& observer) { std::lock_guard<std::mutex> lock (m_mutex) ; m_observers.remove_if ([&](const std::weak_ptr<IObserver>& w) { bool ret = true ; if (!w.expired ()) { ret = w.lock () == observer.lock (); } return ret; }); } template <typename ... Args> void NotifyObservers (Args&&... args) { std::lock_guard<std::mutex> lock (m_mutex) ; auto iter = m_observers.begin (); while (iter != m_observers.end ()) { std::shared_ptr<IObserver> obj (iter->lock()) ; if (obj) { obj->Update ((args)...); ++iter; } else { iter = m_observers.erase (iter); } } }private : std::list<std::weak_ptr<IObserver>> m_observers; std::mutex m_mutex; };class Worker {public : Worker (int a = 1 ,int b = 1 ):m_a (a),m_b (b) {} ~Worker () = default ; void Register (std::weak_ptr<IObserver> observer) { mo.RegisterObserver (std::move (observer)); } void Remove (std::weak_ptr<IObserver> observer) { mo.RemoveObserver (observer); } void multiply () { int result = m_a * m_b; std::vector<std::any> args{ result,m_a,m_b}; mo.NotifyObservers (args); }private : int m_a; int m_b; ManageObserver mo; };class ConcreteObserver : public IObserver {public : ConcreteObserver (int id) :m_id (id), result (0 ) {} virtual ~ConcreteObserver () = default ; void Update (std::vector<std::any> args) { result = getArg <int >(0 , args); int a = getArg <int >(1 , args); int b = getArg <int >(2 , args); std::cout<<" Awake : " << a << " * " << b << " = " << result <<" id: " << m_id << std::endl; }private : template <typename T> T getArg (int index, std::vector<std::any>& args) { T ret; try { ret = std::any_cast <T>(args[index]); } catch (...) { std::cout << "Err type or index!" << std::endl; } return ret; }private : int m_id; int result; };int main () { Worker w (3 , 5 ) ; std::shared_ptr<ConcreteObserver> pObserver1 = std::make_shared <ConcreteObserver>(1 ); std::shared_ptr<ConcreteObserver> pObserver2 = std::make_shared <ConcreteObserver>(2 ); { std::shared_ptr<ConcreteObserver>pObserver3 = std::make_shared <ConcreteObserver>(3 ); std::shared_ptr<ConcreteObserver>pObserver4 = std::make_shared <ConcreteObserver>(4 ); w.Register (pObserver1); w.Register (pObserver2); w.Register (pObserver3); w.Register (pObserver4); } w.multiply (); std::cout << "\n" ; w.Remove (pObserver1); w.Remove (pObserver2); w.multiply (); return 0 ; }