【设计模式】观察者模式

观察者模式

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

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

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感兴趣的对象,就会被通知到,进而它可以去处理事物,以下是运行结果:

相关推荐
唐诺4 小时前
几种广泛使用的 C++ 编译器
c++·编译器
南宫生4 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
sanguine__5 小时前
Web APIs学习 (操作DOM BOM)
学习
冷眼看人间恩怨5 小时前
【Qt笔记】QDockWidget控件详解
c++·笔记·qt·qdockwidget
红龙创客5 小时前
某狐畅游24校招-C++开发岗笔试(单选题)
开发语言·c++
Lenyiin5 小时前
第146场双周赛:统计符合条件长度为3的子数组数目、统计异或值为给定值的路径数目、判断网格图能否被切割成块、唯一中间众数子序列 Ⅰ
c++·算法·leetcode·周赛·lenyiin
yuanbenshidiaos7 小时前
c++---------数据类型
java·jvm·c++
数据的世界017 小时前
.NET开发人员学习书籍推荐
学习·.net
四口鲸鱼爱吃盐7 小时前
CVPR2024 | 通过集成渐近正态分布学习实现强可迁移对抗攻击
学习
十年一梦实验室7 小时前
【C++】sophus : sim_details.hpp 实现了矩阵函数 W、其导数,以及其逆 (十七)
开发语言·c++·线性代数·矩阵