设计模式 | 观察者模式
libdash播放器使用的就是观察者模式的设计方式!
什么是观察者模式:
- 观察者模式是软件设计模式的一种。
- 在此种模式中,一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知。
- 这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来 实时事件处理 系统。
使用动机:
- 观察者模式定义一种交互,即发布-订阅:
- 一个对象当自身状态发生改变时,会发出通知,但是并不知道谁是他的接收者,但每个接收者都会接收到通知,这些接受者称为观察者
- 作为对通知的响应,每个观察者都将查询目标状态,然后改变自身的状态以和目标状态进行同步。
使用场景:
- 使对象封装为独立的改变和使用;
- 一个对象改变同时需要改变其它对象,而不知道具体有多少对象需要改变;
- 不希望对象是紧耦合的;
结构
- Subject:抽象目标,知道它的观察者,提供注册和删除观察者对象的接口
- Observer:抽象观察者,为那些在目标发生改变时需获得通知的对象定义一个更新接口
- ConcreteSubject:具体目标,存储对象状态,状态改变时,向各个观察者发出通知
- ConcreteObserver:具体观察者,维护一个指向ConcreteSubject对象的引用,存储有关状态,实现更新接口update,使自身状态与目标的状态保持一致
优缺点:
- 目标和观察者之间松耦合
- 支持广播通信:Subject发送的通知不需要指定它的接受者。通知被自动广播给所有已向该目标对象登记的有关对象。
- 意外的更新:看似无害的操作可能会引起观察者错误的更新。
示例代码:
该部分转载自作者:一去丶二三里
创建抽象主题:
提供关于注册、注销、通知观察者的接口:
// subject.h
#ifndef SUBJECT_H
#define SUBJECT_H
class IObserver;
// 抽象主题
class ISubject
{
public:
virtual void Attach(IObserver *) = 0; // 注册观察者
virtual void Detach(IObserver *) = 0; // 注销观察者
virtual void Notify() = 0; // 通知观察者
};
#endif // SUBJECT_H
创建具体主题:
抽象主题的具体实现,用于管理所有的观察者:
// concrete_subject.h
#ifndef CONCRETE_SUBJECT_H
#define CONCRETE_SUBJECT_H
#include "subject.h"
#include "observer.h"
#include <iostream>
#include <list>
using namespace std;
// 具体主题
class ConcreteSubject : public ISubject
{
public:
ConcreteSubject() { m_fPrice = 10.0; }
void SetPrice(float price) {
m_fPrice = price;
}
void Attach(IObserver *observer) {
m_observers.push_back(observer);
}
void Detach(IObserver *observer) {
m_observers.remove(observer);
}
void Notify() {
list<IObserver *>::iterator it = m_observers.begin();
while (it != m_observers.end()) {
(*it)->Update(m_fPrice);
++it;
}
}
private:
list<IObserver *> m_observers; // 观察者列表
float m_fPrice; // 价格
};
#endif // CONCRETE_SUBJECT_H
创建抽象观察者:
提供一个 Update() 接口,用于更新价格:
// observer.h
#ifndef OBSERVER_H
#define OBSERVER_H
// 抽象观察者
class IObserver
{
public:
virtual void Update(float price) = 0; // 更新价格
};
#endif // OBSERVER_H
创建具体观察者:
抽象观察者的具体实现,当接收到通知后,调整对应的价格:
// concrete_observer.h
#ifndef CONCRETE_OBSERVER_H
#define CONCRETE_OBSERVER_H
#include "observer.h"
#include <iostream>
#include <string>
using namespace std;
// 具体观察者
class ConcreteObserver : public IObserver
{
public:
ConcreteObserver(string name) { m_strName = name; }
void Update(float price) {
cout << m_strName << " - price: " << price << "\n";
}
private:
string m_strName; // 名字
};
#endif // CONCRETE_OBSERVER_H
创建客户端:
创建主题以及对应的观察者,并添加观察者并更新价格:
// main.cpp
#include "concrete_subject.h"
#include "concrete_observer.h"
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) { if(p){delete(p); (p)=NULL;} }
#endif
int main()
{
// 创建主题、观察者
ConcreteSubject *pSubject = new ConcreteSubject();
IObserver *pObserver1 = new ConcreteObserver("Jack Ma");
IObserver *pObserver2 = new ConcreteObserver("Pony");
// 注册观察者
pSubject->Attach(pObserver1);
pSubject->Attach(pObserver2);
// 更改价格,并通知观察者
pSubject->SetPrice(12.5);
pSubject->Notify();
// 注销观察者
pSubject->Detach(pObserver2);
// 再次更改状态,并通知观察者
pSubject->SetPrice(15.0);
pSubject->Notify();
SAFE_DELETE(pObserver1);
SAFE_DELETE(pObserver2);
SAFE_DELETE(pSubject);
getchar();
return 0;
}
运行结果:
Jack Ma - price: 12.5
Pony - price: 12.5
Jack Ma - price: 15