描述
观察者模式就是MVC模式中的View部分,所以应用也比较多。观察者模式定义了一种一对多的依赖关系,当一个对象的状态改变时,就自动通知并更新依赖关系。其实观察者这种一对多的关系就像拍卖。每个竞标者都有一个编号牌用来竞价。一旦拍卖开始,当一个竞标者(Observer
)举牌,拍卖人(Subject
)就会提高出价,并将新的价格告诉所有的竞标者(Observer
)已进行新一轮的竞价。
结构
Subject
为独立的抽象对象,Observer
为用户接口。Subject
提示Observer
去做什么,而Observer
就可以回调给Subject
需要的信息。
具体操作
- 区分独立的功能和公共的功能
- 将独立功能建模为
Subject
- 将公共的功能建模为
Observer
结构 Subject
只与Observer
基类耦合- 客户端配置观察者们
- 观察者们注册到
Subject
中 Subject
广播事件到所有已经注册的观察者们Subject
会将信息推送给观察者们,而观察者们会从中选取它们需要的信息
案例
1. 对比案例
- 没有应用观察者模式
class DivObserver
{
int m_div;
public:
DivObserver(int div)
{
m_div = div;
}
void update(int val)
{
cout << val << " div " << m_div << " is " << val / m_div << '\n';
}
};
class ModObserver
{
int m_mod;
public:
ModObserver(int mod)
{
m_mod = mod;
}
void update(int val)
{
cout << val << " mod " << m_mod << " is " << val % m_mod << '\n';
}
};
class Subject
{
int m_value;
DivObserver m_div_obj;
ModObserver m_mod_obj;
public:
Subject(): m_div_obj(4), m_mod_obj(3){}
void set_value(int value)
{
m_value = value;
notify();
}
void notify()
{
m_div_obj.update(m_value);
m_mod_obj.update(m_value);
}
};
int main()
{
Subject subj;
subj.set_value(14);
}
Output
14 div 4 is 3
14 mod 3 is 2
- 应用观察者模式
#include <iostream>
#include <vector>
using namespace std;
class Observer
{
public:
virtual void update(int value) = 0;
};
class Subject
{
int m_value;
vector< Observer * > m_views;
public:
void attach(Observer *obs)
{
m_views.push_back(obs);
}
void set_val(int value)
{
m_value = value;
notify();
}
void notify()
{
for (int i = 0; i < m_views.size(); ++i)
m_views[i]->update(m_value);
}
};
class DivObserver: public Observer
{
int m_div;
public:
DivObserver(Subject *model, int div)
{
model->attach(this);
m_div = div;
}
/* virtual */void update(int v)
{
cout << v << " div " << m_div << " is " << v / m_div << '\n';
}
};
class ModObserver: public Observer
{
int m_mod;
public:
ModObserver(Subject *model, int mod)
{
model->attach(this);
m_mod = mod;
}
/* virtual */void update(int v)
{
cout << v << " mod " << m_mod << " is " << v % m_mod << '\n';
}
};
int main()
{
Subject subj;
DivObserver divObs1(&subj, 4);
DivObserver divObs2(&subj, 3);
ModObserver modObs3(&subj, 3);
subj.set_val(14);
}
Output
14 div 4 is 3
14 div 3 is 4
14 mod 3 is 2
2.Class inheritance VS type inheritance
#include <iostream>
#include <vector>
using namespace std;
class AlarmListener
{
public:
virtual void alarm() = 0;
};
class SensorSystem
{
vector < AlarmListener * > listeners;
public:
void attach(AlarmListener *al)
{
listeners.push_back(al);
}
void soundTheAlarm()
{
for (int i = 0; i < listeners.size(); i++)
listeners[i]->alarm();
}
};
class Lighting: public AlarmListener
{
public:
/*virtual*/void alarm()
{
cout << "lights up" << '\n';
}
};
class Gates: public AlarmListener
{
public:
/*virtual*/void alarm()
{
cout << "gates close" << '\n';
}
};
class CheckList
{
virtual void localize()
{
cout << " establish a perimeter" << '\n';
}
virtual void isolate()
{
cout << " isolate the grid" << '\n';
}
virtual void identify()
{
cout << " identify the source" << '\n';
}
public:
void byTheNumbers()
{
// Template Method design pattern
localize();
isolate();
identify();
}
};
// class inheri. // type inheritance
class Surveillance: public CheckList, public AlarmListener
{
/*virtual*/void isolate()
{
cout << " train the cameras" << '\n';
}
public:
/*virtual*/void alarm()
{
cout << "Surveillance - by the numbers:" << '\n';
byTheNumbers();
}
};
int main()
{
SensorSystem ss;
ss.attach(&Gates());
ss.attach(&Lighting());
ss.attach(&Surveillance());
ss.soundTheAlarm();
}
Output
gates close
lights up
Surveillance - by the numbers:
establish a perimeter
train the cameras
identify the source
3.
#include <iostream>
#include <vector>
using namespace std;
class Subject {
// 1. "independent" functionality
vector < class Observer * > views; // 3. Coupled only to "interface"
int value;
public:
void attach(Observer *obs) {
views.push_back(obs);
}
void setVal(int val) {
value = val;
notify();
}
int getVal() {
return value;
}
void notify();
};
class Observer {
// 2. "dependent" functionality
Subject *model;
int denom;
public:
Observer(Subject *mod, int div) {
model = mod;
denom = div;
// 4. Observers register themselves with the Subject
model->attach(this);
}
virtual void update() = 0;
protected:
Subject *getSubject() {
return model;
}
int getDivisor() {
return denom;
}
};
void Subject::notify() {
// 5. Publisher broadcasts
for (int i = 0; i < views.size(); i++)
views[i]->update();
}
class DivObserver: public Observer {
public:
DivObserver(Subject *mod, int div): Observer(mod, div){}
void update() {
// 6. "Pull" information of interest
int v = getSubject()->getVal(), d = getDivisor();
cout << v << " div " << d << " is " << v / d << '\n';
}
};
class ModObserver: public Observer {
public:
ModObserver(Subject *mod, int div): Observer(mod, div){}
void update() {
int v = getSubject()->getVal(), d = getDivisor();
cout << v << " mod " << d << " is " << v % d << '\n';
}
};
int main() {
Subject subj;
DivObserver divObs1(&subj, 4); // 7. Client configures the number and
DivObserver divObs2(&subj, 3); // type of Observers
ModObserver modObs3(&subj, 3);
subj.setVal(14);
}
Output
14 div 4 is 3
14 div 3 is 4
14 mod 3 is 2