浅谈C++下观察者模式的实现

news2024/11/25 9:55:06

为什么要有观察者模式

想象一个场景,有一只猫和一群老鼠,当猫出现的时候,每一只老鼠都要逃跑

用最简单的方法实现一个去模拟这一个过程

#include<iostream>

class Mouse_1
{
	public:
		void CatCome()
		{
			std::cout<<"Mouse_1 Run"<<std::endl;	
		}
};

class Mouse_2
{
	public:
		void CatCome()
		{
			std::cout<<"Mouse_2 Run"<<std::endl;	
		}
};

class Cat
{
	public:
		void IamCome()
		{
			std::cout<<"Cat Come!!!"<<std::endl;	
			mouse_1.CatCome();
			mouse_2.CatCome();
		}
	private:
		Mouse_1 mouse_1;
		Mouse_2 mouse_2;
};

int main()
{
	Cat cat;
	cat.IamCome();
	return 0;
}

执行后:

 这么写的话,如果要多增加一只老鼠的话,那么就得把cat的类改为

class Cat
{
	public:
		void IamCome()
		{
			std::cout<<"Cat Come!!!"<<std::endl;	
			mouse_1.CatCome();
			mouse_2.CatCome();
			mouse_3.CatCome();
		}
	private:
		Mouse_1 mouse_1;
		Mouse_2 mouse_2;
		Mouse_3 mouse_3;
};

这样的话每次修改都得修改Cat这个类,不是很方便,那么有没有一种模式可以不用修改这个类去实现添加老鼠的功能,那么就有了观察者模式

观察者模式的实现

首先我们需要定义一个接口,所有的老鼠继承这个接口:

class MosueInterface
{
	public:
		virtual void CatCome()=0;
		virtual ~MosueInterface(){}
};

接着定义两只“mouse”:

class Mouse_1 : public MosueInterface
{
	public:
		void CatCome() override
		{
			std::cout<<"Mouse_1 Run"<<std::endl;	
		}
};

class Mouse_2 : public MosueInterface
{
	public:
		void CatCome() override
		{
			std::cout<<"Mouse_2 Run"<<std::endl;	
		}
};

接下来就要定义老猫了,首先需要一个vector能存储所有的老鼠:

std::vector<MosueInterface*> mice;

在老猫的方法里面定义添加修改这个vector的方法 :

//向vector中添加老鼠
void Add(MosueInterface* mouse) 
{
	mice.push_back(mouse);
}
//从vector中删除老鼠
void Remove(MosueInterface* mouse) 
{
	std::vector<MosueInterface*>::iterator it = std::find(mice.begin(),mice.end(),mouse);
	if(it!=mice.end())
	{
		mice.erase(it);
	}
}

遍历vector,挨个对老鼠发送“我来了的消息”:

void IamCome() 
{
	std::cout<<"Cat Come!!!"<<std::endl;	
	for(const auto i : mice)
		{
			i->CatCome();
		}
}

老猫的总体定义如下: 

class Cat 
{
	public:
		void Add(MosueInterface* mouse) 
		{
			mice.push_back(mouse);
		}
		
		void Remove(MosueInterface* mouse) 
		{
			std::vector<MosueInterface*>::iterator it = std::find(mice.begin(),mice.end(),mouse);
			if(it!=mice.end())
			{
				mice.erase(it);
			}
		}
		void IamCome() 
		{
			std::cout<<"Cat Come!!!"<<std::endl;	
			for(const auto i : mice)
			{
				i->CatCome();
			}
		}
	private:
		std::vector<MosueInterface*> mice;
};

在main中执行事件:

int main()
{
	Cat cat;
	cat.Add(new Mouse_1);
	cat.Add(new Mouse_2);
	cat.IamCome();
	return 0;
}

整体代码如下

#include<iostream>
#include<vector>
#include<algorithm>

class MosueInterface
{
	public:
		virtual void CatCome()=0;
		virtual ~MosueInterface(){}
};


class Mouse_1 : public MosueInterface
{
	public:
		void CatCome() override
		{
			std::cout<<"Mouse_1 Run"<<std::endl;	
		}
};

class Mouse_2 : public MosueInterface
{
	public:
		void CatCome() override
		{
			std::cout<<"Mouse_2 Run"<<std::endl;	
		}
};

class Cat 
{
	public:
		//向vector中添加老鼠
		void Add(MosueInterface* mouse) 
		{
			mice.push_back(mouse);
		}
		//从vector中删除老鼠
		void Remove(MosueInterface* mouse) 
		{
			std::vector<MosueInterface*>::iterator it = std::find(mice.begin(),mice.end(),mouse);
			if(it!=mice.end())
			{
				mice.erase(it);
			}
		}
		void IamCome() 
		{
			std::cout<<"Cat Come!!!"<<std::endl;	
			for(const auto i : mice)
			{
				i->CatCome();
			}
		}
	private:
		std::vector<MosueInterface*> mice;
};

int main()
{
	Cat cat;
	cat.Add(new Mouse_1);
	cat.Add(new Mouse_2);
	cat.IamCome();
	return 0;
}

执行后:

 这时候猫作为被观察者,老鼠作为观察者,这时候执行“我来了”的事件,就不需要每次都修改执行的代码了,只需要在主函数中添加即可

代码抽象出来

我们这时候想把这个观察者和被观察者抽象出来代码如下:

#include<iostream>
#include<vector>
#include<algorithm>

class MosueInterface
{
	public:
		virtual void CatCome()=0;
		virtual ~MosueInterface(){}
};

class CatInterface{
public:
    virtual void Add(MosueInterface* mouse)=0;
    virtual void Remove(MosueInterface* mouse)=0;
    virtual void IamCome()=0;
    virtual ~CatInterface(){}
};

class Mouse_1 : public MosueInterface
{
	public:
		void CatCome() override
		{
			std::cout<<"Mouse_1 Run"<<std::endl;	
		}
};

class Mouse_2 : public MosueInterface
{
	public:
		void CatCome() override
		{
			std::cout<<"Mouse_2 Run"<<std::endl;	
		}
};

class Cat : public CatInterface
{
	public:
		void Add(MosueInterface* mouse) override
		{
			mice.push_back(mouse);
		}
		
		void Remove(MosueInterface* mouse) override
		{
			std::vector<MosueInterface*>::iterator it = std::find(mice.begin(),mice.end(),mouse);
			if(it!=mice.end())
			{
				mice.erase(it);
			}
		}
		void IamCome() override
		{
			std::cout<<"Cat Come!!!"<<std::endl;	
			for(const auto i : mice)
			{
				i->CatCome();
			}
		}
	private:
		std::vector<MosueInterface*> mice;
};

int main()
{
	Cat cat;
	cat.Add(new Mouse_1);
	cat.Add(new Mouse_2);
	cat.IamCome();
	return 0;
}

在许多设计中,经常涉及多个对象都对一个特殊对象中的数据变化感兴趣,而且这多个对象都希望跟踪那个特殊对象中的数据变化,也就是说当对象间存在一对多关系时,在这样的情况下就可以使用观察者模式。当一个对象被修改时,则会自动通知它的依赖对象。

观察者模式是关于多个对象想知道一个对象中数据变化情况的一种成熟的模式。观察者模式中有一个称作“主题”的对象和若干个称作“观察者”的对象,“主题”和“观察者”间是一种一对多的依赖关系,当“主题”的状态发生变化时,所有“观察者”都得到通知。

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

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

相关文章

【MyBatis-Plus】DQL编程控制

1&#xff0c;DQL编程控制 增删改查四个操作中&#xff0c;查询是非常重要的也是非常复杂的操作&#xff0c;这块需要我们重点学习下&#xff0c;这节我们主要学习的内容有: 条件查询方式查询投影查询条件设定字段映射与表名映射 1. 条件查询 1. 条件查询的类 MyBatisPlus…

PHP 训练成绩管理系统mysql数据库web结构apache计算机软件工程网页wamp

一、源码特点 PHP 训练成绩管理系统 是一套完善的web设计系统&#xff0c;对理解php编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为PHP APACHE&#xff0c;数据库 为mysql5.0&#xff0c;使用php语言开发。 …

css设计表格圆角最简单的方法

代码如下&#xff1a; table {width: 100%;/* border-collapse: collapse; */background-color: #FBFBFB; /* 背景颜色; */border-collapse: separate; /* 让border-radius有效 */border-spacing: 0; /*表格中每个格边距设为0*/border: 1px solid #DFDFDF;/*边框*/border-radi…

软件测试面试简历,三年测试项目经验怎么写?

作为三年左右的测试工程师&#xff0c;简历上有五六个项目经历很正常&#xff0c;那如何设计这几个项目&#xff0c;其实设计好三两个就行&#xff0c;面试官能关注到的也只有最新的三两个&#xff0c;两年前的项目也没有关注的必要啦&#xff0c;所以在这两三个项目中一定要体…

mysql8.0 navicat mysql 2059报错

进入mysql安装目录&#xff1a; 输入用户名密码连接mysql 设置密码 刷新 测试连接&#xff0c;连接成功

如何保障业务稳定性?一文详解蚂蚁业务智能可观测平台BOS

随着业务规模的不断扩大以及AI、云计算、大数据等技术的不断发展&#xff0c;大量的企业希望利用上云来加速其数字化转型&#xff0c;全面提升可靠性、安全性和灵活性&#xff0c;并且降低运营成本。 不过对于大多数企业来说&#xff0c;全面上云是一项颇具难度的挑战。这里面…

阿里图标库中图标的下载使用

一 iconfont-阿里巴巴矢量图标库 进去找到你想要的图标 二 点这个 三 点这个 点这个 新建自己的项目 选择这个点下载 解压出来&#xff0c;除了两个demo不要都添加到你的代码中的文件夹保存 四 main.js中全局导入 import ./xxxx/xxxx/iconfont.css 五 页面使用 <…

2 数据类型

数据类型分为基本数据类型和引用数据类型。 基本数据类型有&#xff1a;byte、int、short、long、float、double、char、boolean。占用多少字节&#xff0c;如下表所示。1个字节是8位。

Java面试题【3】

Java面试题——简答题部分 文章目录 Java面试题——简答题部分1.列举几个常用的集合类并指出特点2.Set里的元素是不能重复的&#xff0c;那么用什么方法来区分重复与否呢&#xff0c;是还是equals()&#xff0c;有何区别&#xff1f;3.请描述线程的生命状态&#xff0c;并描述s…

简单分享下怎么创建一个微信小程序

怎么创建一个微信小程序?三招教你这样做!!微信小程序不会做没关系,看我这篇文章就够啦!!实现0基础到大神的瞬间飞跃不是梦!! 戳下方链接即可直达官网&#xff0c;上千种行业精美模板任君挑选&#xff0c;快一起来试试吧&#xff01;让小程序制作不再困难&#xff01;上千个行业…

吉瑞外买项目

目录 1、软件开发整体介绍 软件开发流程 角色分工 软件环境 2、瑞奇外卖项目介绍 项目介绍 产品原型展示 技术选型 功能架构 角色 3、环境搭建 数据库环境搭建 maven项目搭建 4、后台登录功能开发 需求分析 代码开发 5、后台退出功能开发 第一天 1、软件开发整…

ModaHub魔搭社区:腾讯云定义AI Native向量数据库

大模型时代的到来&#xff0c;拥抱大模型成为企业的刚需。 向量数据库通过把数据向量化然后进行存储和查询&#xff0c;可以极大地提升效率和降低成本。它能解决大模型预训练成本高、没有“长期记忆”、知识更新不足、提示词工程复杂等问题&#xff0c;突破大模型在时间和空间…

12.2 ARM处理器概论

目录 ARM处理器概述 ARM公司概述 ARM的含义 ARM公司 ARM产品系列 早先经典处理器 Cortex-A系列 Cortex-R系列 Cortex-M系列 RISC处理器 RISC处理器&#xff08;精简指令集处理器&#xff09; CISC处理器&#xff08;复杂指令集处理器&#xff09; ARM指令集概述 …

MQTT协议原理介绍及如何使用emqx

MQTT协议原理介绍及如何使用emqx 什么是MQTT协议 MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;协议是一种轻量级的、基于发布/订阅模式的通信协议。它最初由IBM开发&#xff0c;用于在低带宽和不稳定的网络环境中传输小型数据包。MQTT协议被广泛应用于物…

二叉树题目:对称二叉树

文章目录 题目标题和出处难度题目描述要求示例数据范围进阶 解法一思路和算法代码复杂度分析 解法二思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;对称二叉树 出处&#xff1a;101. 对称二叉树 难度 3 级 题目描述 要求 给你一个二叉树的根结点 root \t…

Linux的编译器——gcc/g++(预处理、编译、汇编、链接)

文章目录 一.程序实现的两个环境二.gcc如何完成1.预处理2.编译3.汇编4.链接 三.动态库与静态库对比下二者生成的文件大小 四.gcc常用选项 前言&#xff1a; 本文主要认识与学习Linux环境下常用的编译器——gcc&#xff08;编译C代码&#xff09;/g&#xff08;编译C代码&#x…

ECharts社区 合集整理

1、PPChart 地址&#xff1a;http://ppchart.com/#/ 2、DataInsight 地址&#xff1a;http://chartlib.datains.cn/echarts 3、isqqw 地址&#xff1a;https://www.isqqw.com/ 4、makeapie 地址&#xff1a;https://www.makeapie.cn/echarts 5、Chart.Top 地址: http://chart.…

【二维属性+贪心+双指针】Wannafly 挑战赛15 A

Wannafly挑战赛15_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ (nowcoder.com) 题意&#xff1a; 思路&#xff1a; 经典中的经典中的经典 还是一样双指针把可行解放入DS中&#xff0c;然后求最优解 值得注意的是&#xff0c;我们说的双指针的单调性&#xff0c…

SpringCloudAlibaba集成RocketMQ实现分布式事务事例(一)

SpringCloudAlibaba集成RocketMQ实现分布式事务事例(一) 业务需求 用户请求订单微服务 order-service 接口删除订单(退货),删除订单时需要调用 account-service的方法给账户增加余额,一个典型的分布式事务问题。 代码实现 事务消息有三种状态: TransactionStatus.Commi…

第162天:应急响应-网站入侵篡改指南Webshell内存马查杀漏洞排查时间分析

知识点 #知识点 -网页篡改与后门攻击防范应对指南 主要需了解&#xff1a;异常特征&#xff0c;处置流程&#xff0c;分析报告等 主要需了解&#xff1a;日志存储&#xff0c;Webshell检测&#xff0c;分析思路等 掌握&#xff1a; 中间件日志存储&#xff0c;日志格式内容介绍…