设计模式之观察者模式
一、什么是观察者模式?
观察者模式又被称为发布-订阅(Publish/Subscribe)模式:定义对象的一种一对多的依赖关系。当一个对象的状态发生改变时,所有依赖于它的对象都得到通知被自动更新。需要考虑到低耦合和易用性,要保证高度的协作:观察者模式的结构图如下:
- Subject:目标对象(抽象描述被观察者),一个目标可以被多个观察者观察,同时目标对象提供观察者的注册和反注册。通俗的讲就是,Subject讲所有的观察者对象保存在一个集合中(数量不限),同时Subject对外提供“注册观察”和“取消注册”的方法。
- Observer:抽象观察者的接口。抽象的Observe”就是“Subject观察者集合中的一员,当Observer“关注”的事件状态发生改变时,Observer在注册观察时提供的动作将自动被执行。因此抽象的Observer在注册时需要提供一个更新接口。
- ConcreteSubject:具体的目标实现对象。ConcreteSubject就是Subject的具体实例化,它专门来维护观察者们观察的“事件”,当“事件”状态发生改变时,ConcreteSubject会通知所有“关注”该“事件”的观察者。
- ConcreteObserver:观察者的具体实现对象。ConcreteObserver就是Observer的具体实例化,ConcreteObserver在注册了观察的“事件”后,一旦“事件”状态发生改变,ConcreteObserver提供的更新接口将自动被执行。
观察者模式的优缺点:
- 优点:实现观察者和目标之间的抽象耦合,动态联动,且支持广播通信。
- 缺点:可能会引起无谓的操作(由于观察者模式都是广播通知,不论观察者要与不要,每次观察者都会被调用观察者的更新方法,如果观察者不需要处理,就会引起无谓操作,在设计架构时需要注意)。
观察者模式的本质:触发联动。
二、观察者模式实例:
-
实现一个简单的观察者模式
#include <iostream> #include <list> //抽象的观察者接口(观察者) template<class T> class Observer { public: virtual void Update(T state) = 0; virtual ~Observer() {} }; //抽象的目标对象(通知者) template<class T> class Subject { public: virtual void Attach(Observer<T>*) = 0; virtual void Detach(Observer<T>*) = 0; virtual void Notify() = 0; virtual ~Subject() {} }; //具体的观察者1 template<class T> class ConcreteObserver1 :public Observer<T> { public: ConcreteObserver1(Subject<T>* pSubject) :m_pSubject(pSubject) {} void Update(T state) { std::cout << "ConcreteObserver1 Get Update:" << state << std::endl; } private: Subject<T>* m_pSubject; }; //具体的观察者2 template<class T> class ConcreteObserver2 :public Observer<T> { public: ConcreteObserver2(Subject<T>* pSubject) :m_pSubject(pSubject) {} void Update(T state) { std::cout << "ConcreteObserver2 Get Update:" << state << std::endl; } private: Subject<T>* m_pSubject; }; //具体的目标实现对象 template<class T> class ConcreteSubject :public Subject<T> { public: //注册 virtual void Attach(Observer<T>* pOb) { m_observersLst.push_back(pOb); } //取消注册 virtual void Detach(Observer<T>* pOb) { m_observersLst.remove(pOb); } //通知 virtual void Notify() { for (auto pOb : m_observersLst) pOb->Update(m_state); } //设置状态 void SetState(T state) { m_state = state; } private: T m_state; std::list<Observer<T>*> m_observersLst; }; int main() { //1.创建目标对象 ConcreteSubject<int>* pcs = new ConcreteSubject<int>(); //2.创建观察者 Observer<int>* pob1 = new ConcreteObserver1<int>(pcs); Observer<int>* pob2 = new ConcreteObserver2<int>(pcs); //3.注册观察者接口 pcs->Attach(pob1); pcs->Attach(pob2); //4.更新状态并通知 pcs->SetState(666); pcs->Notify(); //5.注销观察者1 pcs->Detach(pob1); //6.更新状态并通知 pcs->SetState(777); pcs->Notify(); pcs->Detach(pob2); delete pob1; delete pob2; delete pcs; return 0; }
-
模拟实现QT中的信号槽机制
#include <iostream> #include <vector> using namespace std; template <class T> class SlotBase { public: virtual void slotFunction(T param)=0; virtual ~SlotBase()=default; }; template<class TRecver,class T> class Slot:public SlotBase<T> { private: TRecver* m_pRecver; //接收者,构造中初始化 void(TRecver::*m_func)(T param); //定义一个接收者类中的成员函数指针 public: Slot(TRecver* pObj,void(TRecver::*func)(T)) { this->m_pRecver=pObj; this->m_func=func; //使用类外的接收者类的对象指针与接收者类中的成员函数指针进行初始化 } void slotFunction(T param) override { (m_pRecver->*m_func)(param);// "->*"成员对象指针调用类内的成员函数 } }; template <class T> class Signal { private: vector<SlotBase<T>*> m_signal_vector; public: template<class TRecver> void addSlot(TRecver* pObj,void(TRecver::*func)(T)) { m_signal_vector.push_back(new Slot<TRecver,T>(pObj,func)); } void operator()(T param) { for(SlotBase<T>* p:m_signal_vector) { p->slotFunction(param); } } }; class Recver1 { public: void func(int param) { cout<<"this is Recver1,param:"<<param<<endl; } }; class Recver2 { public: void func(int param) { cout<<"this is Recver2,param:"<<param<<endl; } }; class SendObj { public: Signal<int> m_valueChanged; public: void testSignal(int value) { m_valueChanged(value); } }; #define connect(sender,signal,recver,method) (sender)->signal.addSlot(recver,method) int main() { cout << "Hello World!" << endl; Recver1* r1=new Recver1; Recver2* r2=new Recver2; SendObj* sd=new SendObj; connect(sd,m_valueChanged,r1,&Recver1::func); connect(sd,m_valueChanged,r2,&Recver2::func); sd->testSignal(10000); return 0; }