观察者模式Observer Pattern
UML类图
Observer(观察者基类)
- 为那些在目标发生改变时需获得通知的对象定义一个更新接口。
Subject(观察目标基类,可以理解为通知者)
-
目标知道它的观察者(它被那些观察者观察)。可以有任意多个观察者观察同一个目标;
-
提供注册和注销观察者对象的接口。
ConcreteObserver(具体的观察者)
-
维护一个指向ConcreteSubject对象的引用;
-
存储有关状态,这些状态应与目标的状态保持一致;
-
实现Observer的更新接口以使自身状态与目标的状态保持一致。
ConcreteSubject(具体的被观察者即观察目标)
-
将有关状态存入各ConcreteObserver对象;
-
当它的状态发生改变时,向它的各个观察者发出通知。
一、定义:观察者模式又被称为:发布订阅模式
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,让它们能够自动更新自己。可以理解为一个对象行为的改变,其相关联的对象都会得到通知,并自动产生对应的行为。
二、适用场景:在以下任一情况下都可以使用观察者模式:
-
当一个抽象模型有两个方面,其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立的改变和复用;
-
当对一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变;
-
当一个对象必须通知其它对象,而它又不能假定其它对象是谁;也就是说,你不希望这些对象是紧密耦合的。
-
凡是涉及到消息更新、广播机制、消息传递、链式触发都可以考虑使用观察者模式
三、“观察”不是“直接调用”
实现观察者模式的时候要注意,观察者和被观察对象之间的互动关系不能体现成类之间的直接调用,否则就将使观察者和被观察对象之间紧密的耦合起来,从根本上违反面向对象的设计的原则。不管是观察者“观察”观察对象,还是被观察者将自己的改变“通知”观察者,都不应该直接调用。
四、实现形式:
实现观察者模式有非常多形式,比较直观的一种是使用一种“注册——通知——撤销注册”的形式。
观察者模式按照以下方式进行协作:
-
当ConcreteSubject发生任何可能导致其观察者与其本身状态不一致的改变时,它将通知它的各个观察者;
-
在得到一个具体目标的改变通知后,ConcreteObserver对象可向目标对象查询信息。ConcreteObserver使用这些信息以使它的状态与目标对象的状态一致。
五、应用实例:
-
拍卖的时候,拍卖师观察最高标价,然后通知给其他竞价者竞价。
-
西游记里面悟空请求菩萨降服红孩儿,菩萨洒了一地水招来一个老乌龟,这个乌龟就是观察者,他观察菩萨洒水这个动作。
-
对同一组数据进行统计分析时候, 我们希望能够提供多种形式的表示 (例如以表格进行统计显示、柱状图统计显示、百分比统计显示等)。这些表示都依赖于同一组数据, 我们当然需要当数据改变的时候, 所有的统计的显示都能够同时改变。
六、实例代码
点击查看代码
/*
*一般情况下,观察目标只有一个,即一对多的关系
*/
// observer.h
#include <list>
//通知的消息类型
enum class NotifyType
{
Eat = 0,
Drink,
Play,
Work,
};
class Observer;
//通知者(观察目标)
class Subject
{
protected:
std::list<Observer*> m_observers;
public:
void attach(Observer*); //注册(添加一个观察者)
void detach(Observer*); //注销(删除一个观察者)
virtual void notify() = 0; //通知
};
//观察者
class Observer
{
public:
virtual void update(NotifyType type) = 0; //更新
virtual ~Observer() {};
};
//具体的观察者:员工A
class WorkerA :public Observer
{
void update(NotifyType type) override;
};
//具体的观察者:员工B
class WorkerB :public Observer
{
void update(NotifyType type) override;
};
//具体的观察者:员工C
class WorkerC :public Observer
{
void update(NotifyType type) override;
};
//具体的通知者:组长
class Leader :public Subject
{
public:
void notify() override;
};
//具体的通知者:经理
class Manager :public Subject
{
public:
void notify() override;
};
//具体的通知者:老板
class Boss :public Subject
{
public:
void notify() override;
};
// observer.cpp
#include "observer.h"
#include <iostream>
void Subject::attach(Observer* obs)
{
m_observers.emplace_back(obs);
}
void Subject::detach(Observer* obs)
{
auto it = m_observers.begin();
while (it != m_observers.end())
{
if (*it == obs)
m_observers.erase(it);
it++;
}
}
void Leader::notify()
{
//组长通知一起去洗脚
std::cout << "\t组长发通知了\n";
for (const auto& elem : m_observers)
{
elem->update(NotifyType::Play);
}
}
void Manager::notify()
{
//经理通知今晚加班
std::cout << "\t经理发通知了\n";
for (const auto& elem : m_observers)
{
elem->update(NotifyType::Work);
}
}
void Boss::notify()
{
//老板通知今晚一起吃饭喝酒
std::cout << "\t老板发通知了\n";
for (const auto& elem : m_observers)
{
elem->update(NotifyType::Eat);
elem->update(NotifyType::Drink);
}
}
void WorkerA::update(NotifyType type)
{
switch (type)
{
case NotifyType::Eat:
std::cout << "WorkerA:\t去吃饭咯。\n";
break;
case NotifyType::Drink:
std::cout << "WorkerA:\t去喝酒咯。\n";
break;
case NotifyType::Play:
std::cout << "WorkerA:\t去洗脚咯。\n";
break;
case NotifyType::Work:
std::cout << "WorkerA:\t装作认真工作的样子。\n";
break;
default:
break;
}
}
void WorkerB::update(NotifyType type)
{
switch (type)
{
case NotifyType::Eat:
std::cout << "WorkerB:\t我不去吃饭。\n";
break;
case NotifyType::Drink:
std::cout << "WorkerB:\t我不去喝酒。\n";
break;
case NotifyType::Play:
std::cout << "WorkerB:\t一起去洗脚咯。\n";
break;
case NotifyType::Work:
std::cout << "WorkerB:\t加你麻痹班!\n";
break;
default:
break;
}
}
void WorkerC::update(NotifyType type)
{
switch (type)
{
case NotifyType::Eat:
std::cout << "WorkerC:\t我先回家了。\n";
break;
case NotifyType::Drink:
std::cout << "WorkerC:\t我不会喝酒。\n";
break;
case NotifyType::Play:
std::cout << "WorkerC:\t这次去哪洗脚?\n";
break;
case NotifyType::Work:
std::cout << "WorkerC:\t我要带孩子先溜了,你们好好加班。\n";
break;
default:
break;
}
}
// main.cpp
#include "observer.h"
int main()
{
//观察目标对象
Subject* leader = new Leader();
Subject* manager = new Manager();
Subject* boss = new Boss();
//观察者对象
Observer* workerA = new WorkerA();
Observer* workerB = new WorkerB();
Observer* workerC = new WorkerC();
//给观察目标添加观察者
leader->attach(workerA);
leader->attach(workerB);
leader->attach(workerC);
manager->attach(workerA);
manager->attach(workerB);
manager->attach(workerC);
boss->attach(workerA);
boss->attach(workerB);
boss->attach(workerC);
//观察目标状态改变发出通知
leader->notify();
manager->notify();
boss->notify();
return 0;
}
参考:
设计模式之观察者模式(c++)