【设计模式】观察者模式

观察者模式

观察者模式也叫做观察者-监听者模式(发布-订阅模式):主要关注的是对象之间的通信,关注的是对象的一对多的关系,也就是多个对象都依赖一个对象,当该对象的状态发生改变时,其他对象都能接收到相应的通知。

例子:基于同一组数据,生成了很多不同的界面来显示,有曲线图显示方式,有圆饼图显示方式,有柱状图显示方式等等...,当底层数据发生改变时,所有基于同一组数据的图像显示都需要修改图像,那么此时有两种实现方式:

1 .所有图形界面模块都去观察底层数据是否做了改变,如果变化,那么读取数据,修改图像显示。

2.此时有一个类似Observer观察者的模块,专门用来观察数据的变化,对某组数据感兴趣的图形界面模块,事先可以向Observer观察者注册,它对哪些数据的变化感兴趣,那么当Observer观察者观测到数据真的发生变化,它会及时的通知对这组数据变化感兴趣的图形界面模块执行相应的代码操作。

简述MVC模式

因为在学习的过程中,很多人不知怎的,将观察者模式和MVC混为一谈。MVC模式最开始出现在WEB开发中,该模式能够很好的做到软件模块的高内聚,低耦合,所以其思想逐渐在各个软件开发领域都有涉及并且引用,MVC模式并不是OOP面向对象的设计模式,它是一种软件整体的架构思想。

M:指的是Model,数据模型层,表示系统底层的数据操作模块

V:指的是View,视图显示层,表示系统对于数据的展示模块

C:指的是Controller,控制层,表示监听用户事件交互,分发处理事件模块

一般来说,MVC模式就是通过Controller控制层监听用户的请求事件,通过访问Model数据层,对数据进行相应的增删改查操作,然后找到合适的View视图用相应的数据进行渲染生成最终的显示视图(可以是图形界面,html web页面,json,protobuff等等),然后再把视图返回给用户。

上图中,简单的罗列了观察者模式的类设计关系,Listener是对某些事件感兴趣的监听者,Listener1和Listener2是监听者具体的实现类,Observer是观察者,负责具体的事件观察并通知监听者处理已发生的事件。

cpp 复制代码
#include <iostream>
#include <string>
#include <unordered_map>
#include <list>

// 观察者抽象类
class Observer
{
public:
	// 处理消息的接口
	virtual void handle(int msgid) = 0;
};
// 第一个观察者实例
class Observer1 : public Observer
{
public:
	void handle(int msgid)
	{
		switch (msgid)
		{
		case 1:
			std::cout << "Observer1 recv 1 msg !" << std::endl;
			break;
		case 2:
			std::cout << "Observer1 recv 2 msg !" << std::endl;
			break;
		default:
			std::cout << "Observer1 recv unknow msg !" << std::endl;
			break;
		}
	}
};
// 第二个观察者实例
class Observer2 : public Observer
{
public:
	void handle(int msgid)
	{
		switch (msgid)
		{
		case 2:
			std::cout << "Observer2 recv 2 msg !" << std::endl;
			break;
		default:
			std::cout << "Observer1 recv unknow msg !" << std::endl;
			break;
		}
	}
};
// 第三个观察者实例
class Observer3 : public Observer
{
public:
	void handle(int msgid)
	{
		switch (msgid)
		{
		case 1:
			std::cout << "Observer3 recv 1 msg !" << std::endl;
			break;
		case 3:
			std::cout << "Observer3 recv 3 msg !" << std::endl;
			break;
		default:
			std::cout << "Observer1 recv unknow msg !" << std::endl;
			break;
		}
	}
};
// 主题类
class Subject
{
public:
	// 给主题增加观察者对象
	void addObserver(Observer *obser, int msgid)
	{
		_submap[msgid].push_back(obser);
		/*auto it = _submap.find(msgid);
		if (it != _submap.end())
		{
			it->second.push_back(obser);
		}
		else
		{
			std::list<Observer*> list;
			_submap.insert({ msgid, list });
		}*/
	}
	// 主题监测发生改变,通知相应的观察者对象处理事件
	void dispatch(int msgid)
	{
		auto it = _submap.find(msgid);
		if (it != _submap.end())
		{
			for (Observer* pobser : it->second)
			{
				pobser->handle(msgid);
			}
		}
	}
private:
	std::unordered_map<int, std::list<Observer*>> _submap;
};
int main()
{
	Subject subject;
	Observer* p1 = new Observer1();
	Observer* p2 = new Observer2();
	Observer* p3 = new Observer3();
	subject.addObserver(p1, 1);
	subject.addObserver(p1, 2);
	subject.addObserver(p2, 2);
	subject.addObserver(p3, 1);
	subject.addObserver(p3, 3);

	int msgid = 0;
	for (;;)
	{
		std::cout << "输入消息id:";
		std::cin >> msgid;
		if (msgid == -1)
		{
			break;
		}
		subject.dispatch(msgid);
	}
	return 0;
}

上述的代码,实现了一个简单的观察者模式,输入消息id,如果有对这个msgid感兴趣的对象,就会被通知到,进而它可以去处理事物,以下是运行结果:

相关推荐
朝九晚五ฺ10 分钟前
【Linux探索学习】第十五弹——环境变量:深入解析操作系统中的进程环境变量
linux·运维·学习
心怀梦想的咸鱼14 分钟前
UE5 第一人称射击项目学习(二)
学习·ue5
心怀梦想的咸鱼16 分钟前
UE5 第一人称射击项目学习(完结)
学习·ue5
红色的山茶花18 分钟前
YOLOv8-ultralytics-8.2.103部分代码阅读笔记-block.py
笔记·深度学习·yolo
召木20 分钟前
C++小白实习日记——Day 2 TSCNS怎么读取当前时间
c++·职场和发展
坚硬果壳_25 分钟前
《硬件架构的艺术》笔记(六):流水线的艺术
笔记·硬件架构
St_Ludwig37 分钟前
C语言 蓝桥杯某例题解决方案(查找完数)
c语言·c++·后端·算法·游戏·蓝桥杯
Jack黄从零学c++1 小时前
opencv(c++)---自带的卷积运算filter2D以及应用
c++·人工智能·opencv
码农小白1 小时前
qt学习:linux监听键盘alt+b和鼠标移动事件
学习·计算机外设
sweetheart7-71 小时前
LeetCode20. 有效的括号(2024冬季每日一题 11)
c++·算法·力扣··括号匹配