用C++跟你聊聊“观察者模型”
从“狼来了”的故事说起
从前有一堆学生,下课偷偷打游戏。但是他们的班主任却总会在不该出现的时间,出现在不该出现的地点–教室后门。 这些学生实在忍无可忍了,他们想了一个办法,买通了他们的班长,由班长为他们放风,当然,谁要请班长放风,就得加入班长的放风小队。一旦有任何风吹草动,班长就会立刻通知他们。 从此,他们过上了无忧无虑的生活,从此,他们与大学失之交臂。
故事中有那些元素呢?有放风的班长、请班长放风的学生、班长的通知名单、班长的通知状态、学生的应对状态,当然,特别重要的还有他们的班主任。
这些元素,便构成了今天这篇”观察者模式“的主题。
观察者模式
Observer 模式应该可以说是应用最多、影响最广的模式之一,因为 Observer 的一个实例 Model/View/Control( MVC) 结构在系统开发架构设计中有着很重要的地位和意义, MVC实现了业务逻辑和表示层的解耦。
在GOF的《设计模式:可复用面向对象软件的基础》一书中对观察者模式是这样说的:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。当一个对象发生了变化,关注它的对象就会得到通知;这种交互也称为发布-订阅(publish-subscribe)。目标是通知的发布者,它发出通知时并不需要知道谁是它的观察者。
如果对Linux编程有一定基础的朋友,肯定知道条件变量吧,条件变量的广播,就是典型的观察者模型。
UML类图
Subject(目标)(就是班长) ——目标知道它的观察者。可以有任意多个观察者观察同一个目标; ——提供注册和删除观察者对象的接口。
Observer(观察者)(就是学生) ——为那些在目标发生改变时需获得通知的对象定义一个更新接口。
ConcreteSubject(具体目标) ——将有关状态存入各ConcreteObserver对象; ——当它的状态发生改变时,向它的各个观察者发出通知。
ConcreteObserver(具体观察者) ——维护一个指向ConcreteSubject对象的引用; ——存储有关状态,这些状态应与目标的状态保持一致; ——实现Observer的更新接口以使自身状态与目标的状态保持一致。
当ConcreteSubject发生任何可能导致其观察者与其本身状态不一致的改变时,它将通知它的各个观察者;
在得到一个具体目标的改变通知后,ConcreteObserver对象可向目标对象查询信息。ConcreteObserver使用这些信息以使它的状态与目标对象的状态一致。
故事转代码
#include<iostream>
#include<vector>
using namespace std;
class abstractstudent {//抽象观察者
public:
virtual void update(int) = 0; //实时更新动态
};
class abstractmonitor {//抽象监听者
public:
//业务配置
virtual void addStudent(abstractstudent*) = 0;//添加新客户
virtual void delStudent(abstractstudent*) = 0;//删除旧用户
virtual void Notify() = 0;//给客户通风报信
};
class student :public abstractstudent {//具体观察者
private:
abstractmonitor* mor;
public:
student(abstractmonitor* mor) :mor(mor) {}
void update(int i) {
if (i == 0)
cout << "危险,隐蔽" << endl;
else
cout << "没事儿,继续耍" << endl;
}
};
class monitor:public abstractmonitor{ //具体监听者
private:
vector<abstractstudent*> vecS;
vector<abstractstudent*>::iterator itS;
int State;
public:
void addStudent(abstractstudent* s) {
vecS.push_back(s);
}
void delStudent(abstractstudent* s) {
itS = vecS.begin();
while (itS != vecS.end())
{
if(*itS == s)
{
vecS.erase(itS);
break;
}
itS++;
}
}
void Notify() {
itS = vecS.begin();
while (itS != vecS.end())
{
(*itS)->update(State);
itS++;
}
}
void setState(int state)
{
State = state;
}
};
int main()
{
monitor* mor = new monitor();
student* stu1 = new student(mor);
student* stu2 = new student(mor);
mor->addStudent(stu1);
mor->addStudent(stu2);
mor->setState(1);
mor->Notify();
mor->delStudent(stu1);
mor->setState(0);
mor->Notify();
delete stu1;
delete stu2;
delete mor;
return 0;
}
应用场景
在以下任一情况下都可以使用观察者模式:
- 当一个抽象模型有两个方面,其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立的改变和复用;
- 当对一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变;
- 当一个对象必须通知其它对象,而它又不能假定其它对象是谁;也就是说,你不希望这些对象是紧密耦合的。
- spark2 sql编程样例:sql操作
- hdu----(1599)最大子矩阵(几何/dp)
- Go语言简单的TCP编程
- hdu---(1054)Strategic Game(最小覆盖边)
- Swagger Starter 1.4.0发布:新增swagger功能开源与全局参数的配置。
- Go语言语法汇总
- 整理的一些模版LCS(连续和非连续)
- 以太坊开发实战(第1部分:智能合约)
- spark2 sql读取数据源编程学习样例2:函数实现详解
- hdu---(4310)Hero(贪心算法)
- 数据库容器化|未来已来
- crontab命令详解
- hdu----(4308)Saving Princess claire_(搜索)
- spark2 sql读取数据源编程学习样例1
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Laravel框架自定义分页样式操作示例
- 使用composer 安装 laravel框架的方法图文详解
- laravel5.6 框架操作数据 Eloquent ORM用法示例
- Python版名片管理系统
- docker-compose部署php项目实例详解
- Linux下通过sed命令对kv方式的配置文件进行修改
- laravel5.6框架操作数据curd写法(查询构建器)实例分析
- PHP基于timestamp和nonce实现的防止重放攻击方案分析
- 怎么在 Linux 中查找一个命令或进程的执行时间
- laravel5.6 框架邮件队列database驱动简单demo示例
- php layui实现前端多图上传实例
- 解决Centos7下crontab+shell脚本定期自动删除文件问题
- PHP使用ajax的post方式下载excel文件简单示例
- laravel邮件发送的实现代码示例
- php curl发送请求实例方法