简单的概述:
Observer模式是建立一个一(Subject)对多(Observer)的依赖关系,并且做到当“一”变化的时候,依赖这个“一”的多也能够同步自动改变。
Observer的结构:
Subject相当于消息的通知者,他提供对于依赖于他的观察者们进行添加注册,删除注销的操作,并且提供了使得依赖于他的所有观察者同步消息的操作Notify。
Observer就是观察者,他提供一个Update操作,注意这里的 Observer 的 Update 操作并不在Observer 改变了Subject目标状态的时候就对自己进行更新,这个更新操作要延迟到 Subject 对象发出 Notify 通知所有 Observer 进行修改(Notify里调用Update)。
除了上面两个主类,我们还需要具体的通知者类,和具体的观察者类。具体的通知者根据具体要求有着自己的Notify通知的函数,同理不同的观察者对于响应通知之后有着自己不同的update更新方式。
所以就清楚了Notify和update要作为纯虚函数存在,Observer,Subject就是抽象类,需要派生各个具体的子类
明白了上面的结构,我们举一个实例
对于苦逼的上班族来说摸鱼再正常不过了,当老板不在的时候,员工可以偷偷干一些自己的事情,但是总不可能看一眼老板摸一下鱼,看一眼老板摸一下鱼....这样肯定不行嘛,那么就需要一个人去通知大家老板有没有来。通知消息的人把和自己关系好的添加到通知名单里面,如果老板来了,就通知一下他们,被通知到的人就去更改自己的状态。
如下图所示:
我们创建一个Observer主类,假如我们摸鱼只能看球或者看股票,那么就要有具体的看球子类和看股票子类,不同的子类干不同的事情
对于Subject主类,我们只有一个秘书子类去当做具体的消息通知者
Observer范例代码:
//观察者模式
class Subject;
//员工 观察者
class Observer {//基类 抽象类
protected:
string _name;
Subject* _sub;
public:
Observer(const string& name, Subject* sub)
:_name(name), _sub(sub) {
cout << "Create Observer" << endl;
}
virtual ~Observer() {
cout << "Destroy Observer" << endl;
}
virtual void update() = 0;//得到消息后 不同的更新方式
};
//不同状态的员工
//去炒股
class StockObserver :public Observer {
public:
StockObserver(const string& name, Subject* sub)
:Observer(name, sub) {
cout << "创建看股票的观察者" << endl;
}
~StockObserver() {
cout << "析构看股票的观察者" << endl;
}
void update();
};
//去看球
class SoccerObserver :public Observer {
public:
SoccerObserver(const string& name, Subject* sub)
:Observer(name, sub) {
cout << "创建看足球的观察者" << endl;
}
~SoccerObserver() {
cout << "析构看足球的观察者" << endl;
}
void update();
};
//消息通知者
class Subject {//抽象类
protected:
list<Observer*>_obslist;//存放着观察者的信息
bool _is_boss;//boss来了没有
string _message;//boss来没来,秘书持有的消息
public:
Subject() :_is_boss(false), _message("boss没来,干自己的事") {
cout << "创建消息通知者" << endl;
}
~Subject() {
removeObserver();
cout << "析构消息通知者" << endl;
}
void SetChanged() {
_is_boss = true;
_message = "boss来了!";
}
void ClearChanged() {
_is_boss = false;
_message = "boss没来,干自己的事";
}
bool GetChanged()const {
//获得老板的状态
return _is_boss;
}
const string& GetMessage()const {
return _message;
}
public:
void addObserver(Observer* obs)//添加观察者
{
_obslist.push_back(obs);
}
void removeObserver(Observer* obs)//移除观察者
{
auto it = find(_obslist.begin(), _obslist.end(), obs);
if (it != _obslist.end())
{
_obslist.erase(it);
}
//_obslist.remove(obs);
}
void removeObserver()//清空所有观察者
{
//重载
_obslist.clear();
}
int countObserver()const //观察者个数
{
return _obslist.size();
}
virtual void notify() = 0;//通知 纯虚函数
};
//秘书类 继承消息通知者
class Secretary :public Subject {
public:
Secretary() {
cout << "创建秘书" << endl;
}
~Secretary() {
cout << "析构秘书" << endl;
}
public:
void notify() {
for (auto& obs : _obslist) {
obs->update();
}
ClearChanged();
}
};
void StockObserver::update()
{
cout << _name << "接收到到信息" << endl;
if (_sub->GetChanged())
{
cout << _sub->GetMessage() << "停止炒股,认真工作" << endl;
}
else
{
cout << "boss 没有来!" << _sub->GetMessage() << endl;
}
}
void SoccerObserver::update()
{
cout << _name << "接收到到信息" << endl;
if (_sub->GetChanged())
{
cout << _sub->GetMessage() << "停止看球,认真工作" << endl;
}
else
{
cout << "boss 没有来!" << _sub->GetMessage() << endl;
}
}
int main()
{
//秘书
Subject* ms = new Secretary();
//员工
Observer* zs = new SoccerObserver("张三", ms);
Observer* xm = new SoccerObserver("小明", ms);
Observer* xh = new StockObserver("小红", ms);
//秘书和员工建立了良好关系,秘书把他们加入自己的受信列表里
ms->addObserver(zs);
ms->addObserver(xm);
ms->addObserver(xh);
//秘书通知一下
ms->SetChanged();
ms->notify();
//把小明移除了
ms->removeObserver(xm);
ms->SetChanged();
ms->notify();
return 0;
}
上面就是一个基本的observer的demo
说明:
1. 在 Observer 模式的实现中,Subject 维护一个 list 作为存储其所有观察者的容器。每当调用 Notify 操作就遍历 list中的 Observer 对象,并广播通知改变状态(调用Observer的Update操作)。
2. 运行示例程序,可以看到当原始数据 Subject 处于状态 “false” 时候,依赖于它的两个观察者都显示 “false”,当原始数据状态改变为 “true” 的时候,依赖于它的两个观察者也都改变为“true”。
3. 可以看到 Observer 与 Subject 两个基类互为耦合,但是这种耦合的双方都依赖于抽象,而不依赖于具体。各个派生子类互相独立
下面我们改写上面的demo
跑了程序我们会发现,没有析构这些员工,即使多加一些delete,会很麻烦的,再者再通知notify函数,它里面是需要obs对象的,有可能调用顺序不对了,程序就死了
delete zs;
delete xm;
delete xh;
那么需要用智能指针去解决,怎么用是取决于具体场景的。
如果说员工没有加班,上下班不需要请示,那么秘书这个通知者就以weak_ptr去管理,因为有可能秘书下班了,员工还没有下班,员工的存活秘书管不着。
如果规定员工上下班就得归秘书管,秘书不下班,员工也走不了~~,这样的话秘书就需要用shared_ptr去控制员工的生存期
下面的话我们以第二种方式去改写一下;
class Subject;
//员工 观察者
class Observer {//基类 抽象类
protected:
string _name;
//Subject* _sub;
weak_ptr<Subject>_sub;
public:
Observer(const string& name, weak_ptr<Subject> sub)
:_name(name), _sub(sub) {
cout << "Create Observer" << endl;
}
virtual ~Observer() {
cout << "Destroy Observer" << endl;
}
virtual void update() = 0;//得到消息后 不同的更新方式
};
//不同状态的员工
//去炒股
class StockObserver :public Observer {
public:
StockObserver(const string& name, weak_ptr<Subject> sub)
:Observer(name, sub) {
cout << "创建看股票的观察者" << endl;
}
~StockObserver() {
cout << "析构看股票的观察者" << endl;
}
void update();
};
//去看球
class SoccerObserver :public Observer {
public:
SoccerObserver(const string& name, weak_ptr<Subject> sub)
:Observer(name, sub) {
cout << "创建看足球的观察者" << endl;
}
~SoccerObserver() {
cout << "析构看足球的观察者" << endl;
}
void update();
};
//消息通知者
class Subject {//抽象类
protected:
//list<Observer*>_obslist;//存放着观察者的信息
list<shared_ptr<Observer>>_obslist;
bool _is_boss;//boss来了没有
string _message;//boss来没来,秘书持有的消息
public:
Subject() :_is_boss(false), _message("boss没来,干自己的事") {
cout << "创建消息通知者" << endl;
}
~Subject() {
removeObserver();
cout << "析构消息通知者" << endl;
}
void SetChanged() {
_is_boss = true;
_message = "boss来了!";
}
void ClearChanged() {
_is_boss = false;
_message = "boss没来,干自己的事";
}
bool GetChanged()const {
//获得老板的状态
return _is_boss;
}
const string& GetMessage()const {
return _message;
}
public:
void addObserver(shared_ptr<Observer>obs)//添加观察者
{
_obslist.push_back(obs);
}
void removeObserver(shared_ptr<Observer> obs)//移除观察者
{
auto it = find(_obslist.begin(), _obslist.end(), obs);
if (it != _obslist.end())
{
_obslist.erase(it);
}
//_obslist.remove(obs);
}
void removeObserver()//清空所有观察者
{
//重载
_obslist.clear();
}
int countObserver()const //观察者个数
{
return _obslist.size();
}
virtual void notify() = 0;//通知 纯虚函数
};
//秘书类 继承消息通知者
class Secretary :public Subject {
public:
Secretary() {
cout << "创建秘书" << endl;
}
~Secretary() {
cout << "析构秘书" << endl;
}
public:
void notify() {
for (auto& obs : _obslist) {
obs->update();
}
ClearChanged();
}
};
void StockObserver::update()
{
cout << _name << "接收到到信息" << endl;
shared_ptr<Subject>pa = _sub.lock();
if (!pa)return;
if (pa->GetChanged())
{
cout << pa->GetMessage() << "停止炒股,认真工作" << endl;
}
else
{
cout << "boss 没有来!" << pa->GetMessage() << endl;
}
}
void SoccerObserver::update()
{
cout << _name << "接收到到信息" << endl;
shared_ptr<Subject>pa = _sub.lock();
if (!pa)return;
if (pa->GetChanged())
{
cout << pa->GetMessage() << "停止看球,认真工作" << endl;
}
else
{
cout << "boss 没有来!" << pa->GetMessage() << endl;
}
}
int main()
{
//秘书
shared_ptr<Subject> ms(new Secretary());
//员工
shared_ptr<Observer> zs (new SoccerObserver("张三", ms));
shared_ptr<Observer> xm(new SoccerObserver("小明", ms)) ;
shared_ptr<Observer> xh(new StockObserver("小红", ms)) ;
//秘书和员工建立了良好关系,秘书把他们加入自己的受信列表里
ms->addObserver(zs);
ms->addObserver(xm);
ms->addObserver(xh);
//秘书通知一下
ms->SetChanged();
ms->notify();
//把小明移除了
ms->removeObserver(xm);
ms->SetChanged();
ms->notify();
return 0;
}
改写成多线程版本的Observer模式
依旧写的是消息发送者生存期到了员工才去析构,把上面demo版增改成如下:
void fun_xm(shared_ptr<Subject>sub)
{
shared_ptr<Observer> xm(new SoccerObserver("小明", sub));
sub->addObserver(xm);//此时秘书没死 xm也没死
cout << "小明上班了."<<endl;
for (int i = 0; i < 5; ++i)
{
this_thread::sleep_for(chrono::microseconds(1000));
}
cout << "小明下班了...." << endl;
}
void fun_zs(shared_ptr<Subject>sub)
{
shared_ptr<Observer> zx(new SoccerObserver("张三", sub));
sub->addObserver(zx);//此时秘书没死 zs也没死
cout << "张三上班了." << endl;
}
void fun_xh(shared_ptr<Subject>sub)
{
shared_ptr<Observer> xh(new StockObserver("小红", sub));
sub->addObserver(xh);//此时秘书没死 xh也没死
cout << "小红上班了." << endl;
}
int main()
{
//秘书
shared_ptr<Subject> sub(new Secretary());
thread tha(fun_zs, sub);
thread thb(fun_xm, sub);
thread thc(fun_xh, sub);
this_thread::sleep_for(chrono::microseconds(200));
for (int i = 0; i < 5; ++i)
{
if (rand() % 2 == 0)
{
sub->SetChanged();
}
else
{
sub->ClearChanged();
}
sub->notify();
cout << endl;
this_thread::sleep_for(chrono::microseconds(500));
}
tha.join();
thb.join();
thc.join();
return 0;
}
想只有一个消息的发送者的话,秘书这个类改写成单例模式