C++ 观察者模式

news2024/10/7 2:49:40

观察者模式(Observer Pattern)是一种行为设计模式,用于在对象之间建立一对多的依赖关系,当一个对象的状态发生变化时,它的所有依赖对象都会得到通知自动更新
在这里插入图片描述
在观察者模式中,主题和观察者之间是松耦合的,主题并不知道观察者的具体实现,只依赖于观察者接口。这种松耦合的关系使得主题和观察者能够独立变化,而不会相互影响。

#include <iostream>
#include <string>
#include <unordered_map>
#include <bits/stdc++.h>
#include <list>
 
 
using namespace std;
/*
* 行为型模式:主要关注的是对象之间的通信
观察者-监听者模式 (发布-订阅模式) 设计模式:主要关注的对象是一对多的关系,
也就是说多个对象都依赖与这一个对象,当这个对象的状态发生改变时,其他对象都能够
接收到相应的通知。
*/
 
class Observer
{
public:
	//处理消息接口
	virtual void handle(int msgid) = 0;
};
 
//第一个观察者实例
class Observer1 : public Observer
{
public:
	void handle(int msgid)
	{
			switch (msgid)
			{
			case 1:
				cout << "Observer1 recv 1 msg!" << endl;
				break;
			case 2:
				cout << "Observer1 recv 2 msg!" << endl;
				break;
			default:
				cout << "Observer1 recv unknow msg! " << endl;
				break;
			}
	}
};
 
//第二个观察者实例
class Observer2 : public Observer
{
public:
	void handle(int msgid)
	{
		
			switch (msgid)
			{
			case 2:
				cout << "Observer2 recv 2 msg!" << endl;
				break;
			default:
				cout << "Observer2 recv unknow msg! " << endl;
				break;
			}
		
	}
};
 
//第三个观察者实例
class Observer3 : public Observer
{
public:
	void handle(int msgid)
	{
	
			switch (msgid)
			{
			case 1:
				cout << "Observer3 recv 1 msg!" << endl;
				break;
			case 3:
				cout << "Observer3 recv 3 msg!" << endl;
				break;
			default:
				cout << "Observer3 recv unknow msg! " << 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
		{
			list<Observer*> lis;
			lis.push_back(obser);
			_subMap.insert({ msgid,lis });
		}*/
	}
 
	//主题检测发生改变,通知相应的观察者对象处理事件
	void dispatch(int msgid) {
		auto it = _subMap.find(msgid);
		if (it != _subMap.end())
		{
			for (Observer* pObser : it->second)
			{
				pObser->handle(msgid);
			}
		}
	}
private:
	unordered_map<int, 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 (;;)
	{
		cout << " 输入消息id: ";
		cin >> msgid;
 
		if (msgid == -1) break;
		subject.dispatch(msgid);
	}
 
	return 0;
}
输入消息id: 2
Observer1 recv 2 msg!
Observer2 recv 2 msg!
 输入消息id: 1
Observer1 recv 1 msg!
Observer3 recv 1 msg!
 输入消息id: 3
Observer3 recv 3 msg!

主要解决的是对象与对象之间的依赖关系,多个对象依赖于一个对象,该对象主要负责检测我们消息发没发生状态改变,有改变了就要通知相应的观察者。

    这里涉及多对象内存开辟问题,需要使用智能指针去优化:
#include<iostream>
#include<unordered_map>
#include<list>
#include<bits/stdc++.h>
#include<memory>
 
class Observer
{
public:
	virtual void handle(int msgid) = 0; //纯虚函数没有具体实现
};
 
class Observer1 : public Observer
{
public:
	void handle(int msgid)
	{
		switch (msgid)
		{
		case 1:
			std::cout << "Observer 1 recv 1 msg!" << std::endl;
			break;
		case 2:
			std::cout << "Observer 1 recv 2 msg!" << std::endl;
			break;
		default:
			std::cout << "Observer 1 recv unknow msg!" << std::endl;
			break;
		}
	}
};
 
class Observer2 : public Observer
{
public:
	void handle(int msgid)
	{
		switch (msgid)
		{
		case 2:
			std::cout << "Observer 2 recv 2 msg!" << std::endl;
			break;
		default:
			std::cout << "Observer 2 recv unknow msg! " << std::endl;
			break;
		}
	}
};
 
class Observer3 : public Observer
{
public:
	void handle(int msgid)
	{
		switch (msgid)
		{
		case 1:
			std::cout << "Obersever 3 recv 1 msg!" << std::endl;
			break;
		case 3:
			std::cout << "Obersever 3 recv 3 msg!" << std::endl;
			break;
		default:
			std::cout << "Observer 3 recv unknow msg! " << std::endl;
			break;
		}
	}
};
 
 
class Subject
{
public:
	void addObserver(std::weak_ptr<Observer> obser, int msgid)
	{
		_subMap[msgid].push_back(obser);
	}
	void dispatch(int msgid)
	{
		auto it = _subMap.find(msgid);
		if (it != _subMap.end())
		{
			for (auto it1 = it->second.begin(); it1 != it->second.end(); ++it1)
			{	
				// 与强指针绑定的弱指针,通过lock函数提升为强指针,可以避免循环引用问题,同时判断所绑定的对象是否被销毁
				std::shared_ptr<Observer>tmp = it1->lock();
				if (tmp) {
					tmp->handle(msgid);
				}
			}
		}
	}
private:
	std::unordered_map<int, std::list<std::weak_ptr<Observer>> > _subMap;
};
 
int main()
{
	Subject subject;
	std::shared_ptr<Observer>p1(new Observer1);
	std::shared_ptr<Observer>p2(new Observer2);
	std::shared_ptr<Observer>p3(new Observer3);
 	
 	// shared_ptr赋值给weak_ptr,绑定
	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;
}

重点就是这里,一开始用弱指针去绑定一些对象subject.addObserver(p1, 1);,通过弱指针提升为强指针,来判断所绑定的对象是否被销毁std::shared_ptr<Observer>tmp = it1->lock();(muduo项目中,channel与TcpConnection对象绑定):

std::shared_ptr<Observer>tmp = it1->lock();
if (tmp) {
	tmp->handle(msgid);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2193426.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue - 路由用法

前端路由就是URL中的hash与组件之间的对应关系。Vue Router是Vue的官方路由。 组成&#xff1a; VueRouter&#xff1a;路由器类&#xff0c;根据路由请求在路由视图中动态渲染选中的组件。<router-link>&#xff1a;请求链接组件&#xff0c;浏览器会解析成<a>。…

S7-200 SMART Modbus RTU常见问题

1.S7-200 SMART 是否支持 Modbus ASCII 通信模式&#xff1f; STEP 7-Micro/WIN SMART 软件未提供Modbus ASCII 通信模式指令库。S7-200 SMART CPU若用于Modbus ASCII 通信时&#xff0c;则需要用户使用自由口通信模式进行编程。 2.S7-200 SMART CPU 集成的RS485 端口&#xf…

毕设 基于大数据情感分析的网络舆情分析系统(源码+论文)

简介 今天学长向大家介绍一个大数据毕设项目 毕设分享 基于大数据情感分析的网络舆情分析系统(源码论文) &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;4分创新点&#xff1a;4分 &#x1f9ff; 项目分享:见文末! 实…

Linux下网络转发功能

1、背景介绍 项目中使用上位机电脑&#xff0c;需要通过网络访问一个Linux主机&#xff0c;但是该Linux主机没有网络直接与上位机相连&#xff0c;只能通过插箱内另外一个Linux主机转发才能访问&#xff0c;示意图如下&#xff1a; 2、网络转发配置 Linux网络中转主机需要进行…

Java体系中的异常

1. 异常 1.1 异常的概念 在Java中&#xff0c;我们将程序执行过程中发生的不正常行为称为异常。异常是在程序运行过程中发生的错误或意外情况&#xff0c;它打破了程序的正常执行流程。在Java中通过面向对象的编程思想&#xff0c;我们也将这些扰乱程序正常执行的行为用类组织…

三菱FX3UPLC定位模式介绍

运行模式的比较 *1用相对定位指令代替。 *2使用相对/绝对定位指令。 *3使用直线插补指令的连续路径功能。 *4使用直线插补指令的连续路径功能。 可单轴运行。 *5.使用表格运行(连续运行功能)。 *6.使用中断定位指令。 *7只支持FX3UFX3UC可编程控制器&#xff0c;使用可变速脉…

设计模式之装饰器模式(Decorator)

一、装饰器模式介绍 装饰模式(decorator pattern) 的原始定义是&#xff1a;动态的给一个对象添加一些额外的职责。 就扩展功能而言&#xff0c;装饰器模式提供了一种比使用子类更加灵活的替代方案。 在软件设计中&#xff0c;装饰器模式是一种用于替代继承的技术&#xff0c;它…

Java语法之异常

1.异常的概念以及体系结构 1.1 异常的概念 在生活中人会生病,比如咳嗽流鼻涕,头晕等,程序也一样,比如:数据格式不匹配,网络不通畅,内存报警等.在Java中,我们把程序执行的不正常行为称为异常. 比如: 1. 算数异常 System.out.println(10 / 0); // 执行结果 Exception in thread &…

python导出requirements.txt的几种方法

整理了python导出requirements.txt的几种方法和流程 Condapippipreqs 最近又碰到整理requirements.txt的问题&#xff0c;有好几种命令可以做到这一点&#xff0c;但是之前整理的时候会输出一堆乱七八糟的包&#xff0c;这次挨个试了所有方法&#xff0c;特此记录。我的平台是a…

【本地缓存】Java 中的 4 种本地缓存

目录 1、手写一个简单的本地缓存1.1、封装缓存实体类1.2、创建缓存工具类1.3、测试 2、Guava Cache2.1、Guava Cache 简介2.2、入门案例2.2.1、引入 POM 依赖2.2.2、创建 LoadingCache 缓存 2.3、Guava Cache 的优劣势和适用场景 3、Caffeine3.1、Caffeine 简介3.2、对比 Guava…

elasticsearch ES DBA常用语句

一、 查看集群状态 curl -uelastic 连接串:端口/_cluster/health?pretty 集群健康有三种状态&#xff1a;green,yellow,red green&#xff1a;所有主要分片、复制分片都可用yellow&#xff1a;所有主要分片可用&#xff0c;但不是所有复制分片都可用red&#xff1a;不是所有…

基于SSM的学生信息管理系统【附源码】

​基于SSM的学生信息管理系统&#xff08;源码L文说明文档&#xff09; 目录 4 系统设计 4.1界面设计原则 4.2功能结构设计 4.3数据库设计 4.3.1数据库概念设计 4.3.2 数据库物理设计 第5章 系统实现 5.1管理员功能实现 5.1.1班级和课程关…

基于企业现状定制化的数字化转型路径和战略性架构规划

如何从企业现状出发规划数字化转型 随着技术的迅猛发展&#xff0c;全球企业都在加速推进数字化转型&#xff0c;以增强市场竞争力并提升运营效率。数字化转型并不是一个统一的模板&#xff0c;它要求企业结合自身的业务现状、行业环境和技术基础&#xff0c;制定个性化的转型…

通信工程学习:什么是B/S浏览器服务器模式

B/S&#xff1a;浏览器服务器模式 B/S&#xff08;Browser/Server&#xff0c;浏览器/服务器&#xff09;模式&#xff0c;又称B/S结构&#xff0c;是Web兴起后的一种网络结构模式。在这种模式中&#xff0c;Web浏览器是客户端最主要的应用软件&#xff0c;系统功能实现的核心部…

分享一个基于.net的学生信息管理系统 C#高校教务管理系统(源码、调试、LW、开题、PPT)

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人 八年开发经验&#xff0c;擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等&#xff0c;大家有这一块的问题可以一起交流&…

计算机毕业设计 智慧物业服务系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

初学Vue(2)

文章目录 监视属性 watch深度监视computed 和 watch 之间的区别 绑定样式&#xff08;class style&#xff09;条件渲染列表渲染基本列表key的原理列表过滤列表排序收集表单中的数据 v-model过滤器&#xff08;Vue3已移除&#xff09; 监视属性 watch 当被监视的属性变化时&am…

使用frp将树莓派穿透到外网

引言 frp官网 最近买了一块树莓派 zero 2w&#xff0c;想要它可以进行远程访问&#xff0c;所以想到了frp这个方案进行穿透&#xff0c;后期会使用树莓派搭建音乐服务器&#xff0c;本人手机内存有点小&#xff0c;xxxx云音乐太占空间&#xff0c;有兴趣的话可以关注后续。 …

在 window 系统下安装 Ubuntu (虚拟机)

文章目录 零、Ubuntu 和 Vmware workstation 资源一、下载 Ubuntu二、下载 Vmware Workstation Pro三、安装 Vmware Workstation Pro四、创建虚拟机五、配置 Ubuntu 零、Ubuntu 和 Vmware workstation 资源 如果觉得自己下载 Ubuntu 和 Vmware workstation 麻烦&#xff0c;也…

如何在 MySQL 中实现数据压缩

如何在 MySQL 中实现数据压缩 在 MySQL 数据库中&#xff0c;数据压缩可以帮助节省存储空间和提高数据传输效率。本篇文章我就一起来看看关于MySQL数据压缩的相关内容。 一、为什么需要数据压缩 随着数据量的不断增长&#xff0c;数据库的存储空间需求也在不断增加。数据压缩…