观察者模式
观察者模式是对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
作用
将一个系统设计成一系列相互协作的类有一个常见的副作用:需要维护相关对象之间的一致性。
观察者模式定义一种交互:
- 一个对象当自身状态发生改变时,会发出通知,但是并不知道谁是他的接收者,但每个接收者都会接收到通知,这些接受者称为观察者。
- 作为对通知的响应,每个观察者都将查询目标状态,然后改变自身的状态以和目标状态进行同步
使用场景
- 使对象封装为独立的改变和使用;
- 一个对象改变同时需要改变其它对象,而不知道具体有多少对象需要改变;
- 不希望对象是紧耦合的。
UML
参与者
- CSubject: 目标,知道它的观察者,提供注册和删除观察者对象的接口
- CObserver:观察者,为那些在目标发生改变时需获得通知的对象定义一个更新接口
- CConcreteSubject:通知所有观察者
- CConcreteObserver:接受目标的通知
优缺点
- 目标和观察者之间松耦合
- 支持广播通信:CSubject发送的通知不需要指定它的接受者。通知被自动广播给所有已向该目标对象登记的有关对象。
- 意外的更新:看似无害的操作可能会引起观察者错误的更新。
代码
#include <string>
#include <list>
class CObserver;
class CSubject
{
public:
virtual ~CSubject() {}
virtual void attach(CObserver* ob) = 0;
virtual void detach(CObserver* ob) = 0;
virtual void notify(const std::string & msg) = 0;
};
class CConcreteSubject : public CSubject
{
public:
CConcreteSubject() = default;
virtual ~CConcreteSubject() = default;
void attach(CObserver* ob) override;
void detach(CObserver* ob) override;
void notify(const std::string & msg) override;
private:
std::list<CObserver*> listObserver_;
};
class CObserver
{
public:
virtual ~CObserver() {}
virtual void update(const std::string & msg) = 0;
};
class CConcreteObserver : public CObserver
{
public:
CConcreteObserver() = default;
CConcreteObserver(const std::string & strName);
virtual ~CConcreteObserver() = default;
void update(const std::string & msg) override;
private:
std::string strName_;
};
#include <iostream>
#include "observer.h"
void CConcreteSubject::attach(CObserver *ob)
{
listObserver_.push_back(ob);
}
void CConcreteSubject::detach(CObserver *ob)
{
listObserver_.remove(ob);
}
void CConcreteSubject::notify(const std::string & msg)
{
for (CObserver * ob : listObserver_)
{
ob->update(msg);
}
}
CConcreteObserver::CConcreteObserver(const std::string & strName) : strName_(strName) {}
void CConcreteObserver::update(const std::string &msg)
{
std::cout << this->strName_ << " get message: " << msg << std::endl;
}
#include "observer.h"
int main()
{
CConcreteObserver a("jack ma");
CConcreteObserver b("pony ma");
CConcreteObserver c("robin li");
CConcreteObserver d("jobs");
CConcreteObserver e("gates");
CConcreteSubject obj;
obj.attach(dynamic_cast<CObserver*>(&a));
obj.attach(dynamic_cast<CObserver*>(&b));
obj.attach(dynamic_cast<CObserver*>(&c));
obj.attach(dynamic_cast<CObserver*>(&d));
obj.attach(dynamic_cast<CObserver*>(&e));
obj.notify("hello");
return 0;
}