观察者模式 Observer / Event
“组件协作”模式:
- 现代软件专业分工之后的第一个结果是“框架与应用程序的划分”,“组件协作”模式通过晚期绑定,来实现框架与应用程序之间的松耦合,是二者之间协作时常用的模式。
- 典型模式
- Template Method
- Observer / Event
- Strategy
动机(Motivation)
- 在软件构建过程中,我们需要为某些对象建立一种“通知依赖关系” ——一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知。如果这样的依赖关系过于紧密,将使软件不能很好地抵御变化。
- 使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系。从而实现软件体系结构的松耦合。
模式定义
定义对象间的一种一对多(变化)的依赖关系,以便当一个对象(Subject)的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。——《设计模式》GoF
单个观察者
个人感觉,类似于用接口类型封装的回调。
示例:
#include <iostream>
using namespace std;
class IProgress
{
public:
virtual ~IProgress() {}
virtual double DoProgress(double v) = 0;
};
// 发布者
class Translation
{
public:
Translation(int factor, IProgress * iProgress)
{
m_Factor = factor;
m_IProgress = iProgress;
}
virtual ~Translation() {}
void DealSomeThing()
{
int factor;
if (m_Factor <= 0) {
factor = 2;
}
else {
factor = 3;
}
if (m_IProgress != nullptr) {
double restult = m_IProgress->DoProgress((double)factor);
cout << "百分比:" << restult << "%" << endl;
}
}
private:
IProgress *m_IProgress;
int m_Factor;
};
// 订阅者 观察者
class Dosomething :public IProgress
{
public:
Dosomething(double n) { m_num = n; }
virtual ~Dosomething() {};
virtual double DoProgress(double v) override
{
return (v + m_num);
}
void DoThing()
{
Translation trans(1, this);
trans.DealSomeThing();
}
private:
double m_num;
};
int main()
{
Dosomething do_some_thing(12);
do_some_thing.DoThing();
getchar();
return 0;
}
输出:
百分比:15%
多个观察者
用一个数据结构把接口引用存起来进行遍历管理。
使用接口的部分是相对稳定的,接口具体的实现应该是相对变化的比较多的。
代码:
#include <iostream>
#include <vector>
using namespace std;
class IProgress
{
public:
virtual ~IProgress() {}
virtual double DoProgress(double v) = 0;
};
// 发布者
class Translation
{
public:
Translation(int factor)
{
m_Factor = factor;
}
virtual ~Translation() {}
void DealSomeTrans()
{
// 模拟一些过程
int factor;
if (m_Factor <= 0) {
factor = 2;
}
else {
factor = 3;
}
if (m_IProgress.size() > 0) {
for (int i = 0; i < m_IProgress.size(); i++) {
double restult = m_IProgress[i]->DoProgress((double)factor);
cout << "百分比:" << restult << "%" << endl;
}
// 用迭代器
/* for (vector<IProgress *>::iterator itor = m_IProgress.begin(); itor != m_IProgress.end(); itor++) {
double restult = (*itor)->DoProgress((double)factor);
cout << "百分比:" << restult << "%" << endl;
}*/
}
}
void Add(IProgress* progress)
{
m_IProgress.push_back(progress);
}
void Remove(IProgress* progress)
{
vector<IProgress *>::iterator itor = m_IProgress.begin();
while (itor != m_IProgress.end())
{
if (*itor == progress) {
// 删除一个元素之后,迭代器已经指向了被删除元素的下一个元素
itor = m_IProgress.erase(itor);
}
else {
itor++;
}
}
}
private:
vector<IProgress *> m_IProgress;
int m_Factor;
};
// 订阅者 观察者
class AddSomething :public IProgress
{
public:
AddSomething(double n) { m_num = n; }
virtual ~AddSomething() {};
virtual double DoProgress(double v) override
{
return (v + m_num);
}
private:
double m_num;
};
// 订阅者 观察者
class MultiSomething :public IProgress
{
public:
MultiSomething(double n) { m_num = n; }
virtual ~MultiSomething() {};
virtual double DoProgress(double v) override
{
return (v * m_num);
}
private:
double m_num;
};
int main()
{
AddSomething addSome(5.0);
MultiSomething multiSome(5.0);
Translation trans(1);
trans.Add(&addSome);
trans.Add(&multiSome);
trans.DealSomeTrans();
cout << "-------" << endl;
trans.Remove(&addSome);
trans.DealSomeTrans();
getchar();
return 0;
}
输出:
百分比:8%
百分比:15%
-------
百分比:15%
类图
▲ 上面的示例代码中,没有拆分 Subject 和 ConcreteSubject 了,全部写在一起了。
要点总结
- 使用面向对象的抽象,Observer模式使得我们可以独立地改变目标与观察者,从而使二者之间的依赖关系达致松耦合。 // 独立的更改就是松耦合的意思。
- 目标发送通知时,无需指定观察者,通知(可以携带通知信息作为参数)会自动传播。
- 观察者自己决定是否需要订阅通知,目标对象对此一无所知。
- Observer模式是基于事件的UI框架中非常常用的设计模式,也是MVC模式的一个重要组成部分。
参考:GeekBand
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了