当前位置: 首页 > news >正文

重温设计模式--观察者模式

文章目录

  • 观察者模式(Observer Pattern)概述
  • 观察者模式UML图
  • 作用:
    • 实现对象间的解耦
    • 支持一对多的依赖关系
    • 易于维护和扩展
  • 观察者模式的结构
    • 抽象主题(Subject):
    • 具体主题(Concrete Subject):
    • 抽象观察者(Observer):
    • 具体观察者(Concrete Observer):
  • C++ 代码示例1
  • C++代码示例2

观察者模式(Observer Pattern)概述

定义:
观察者模式又被称作发布 - 订阅模式,它是一种行为型设计模式。在这种模式中,存在一个被观察的对象(主题,Subject)以及多个对该主题状态变化感兴趣的观察者(Observer)对象。当主题的状态发生改变时,它会主动通知所有已注册的观察者,观察者们可以根据收到的通知做出相应的响应,从而实现对象之间的一种松耦合的交互关系。

观察者模式:定义了一种一对多的依赖关系,让多个观察者对象同时监听同一主题对象,当这个主题对象发生变化时,能够通知到所有观察者,使他们能够自动更新自己

观察者模式UML图

在这里插入图片描述

作用:

实现对象间的解耦

主题对象和观察者对象之间相互依赖的关系比较松散,主题只负责在自身状态改变时通知观察者,而不用关心观察者具体会做什么操作;观察者也只需要关注主题的通知,不用了解主题内部状态变化的具体实现细节,这样使得它们可以独立地进行修改和扩展,降低了代码的耦合度。

支持一对多的依赖关系

一个主题可以有多个观察者关注它的状态变化,当主题状态更新时,能同时通知到所有相关的观察者,方便实现一些需要多方响应的业务场景,比如在一个股票交易系统中,当某支股票价格变化(主题状态改变),多个关注该股票的股民客户端(观察者)都能及时收到通知并做出相应决策。

易于维护和扩展

如果要新增观察者或者改变主题的通知逻辑等,相对来说比较容易实现,对其他部分的代码影响较小,能够灵活应对业务需求的变化。

观察者模式的结构

抽象主题(Subject):

它定义了注册、移除观察者以及通知观察者等方法的接口,维护了一个观察者列表,用于记录所有注册的观察者对象,当自身状态改变时,通过调用通知方法来告知所有观察者。

具体主题(Concrete Subject):

实现了抽象主题中定义的接口,具体管理观察者的注册和移除操作,并且在自身内部状态发生变化时,按照约定的通知机制去通知所有已注册的观察者。它持有自身实际的业务数据和状态信息。

抽象观察者(Observer):

定义了一个更新(update)方法的接口,当接收到主题的通知时,具体的观察者实现类会通过这个方法来执行相应的业务逻辑,以对主题状态变化做出响应。

具体观察者(Concrete Observer):

实现了抽象观察者中定义的更新方法,在该方法中编写具体的业务逻辑,明确在收到主题通知后自身要进行的操作,比如更新界面显示、进行数据记录等操作。

C++ 代码示例1

以下是一个简单的基于观察者模式的示例代码,模拟一个气象站发布天气数据,多个客户端(观察者)接收并处理天气信息的场景:

#include <iostream>
#include <vector>// 抽象观察者
class Observer
{
public:virtual void update(float temperature, float humidity, float pressure) = 0;
};// 抽象主题
class Subject 
{
public:virtual void registerObserver(Observer* o) = 0;virtual void removeObserver(Observer* o) = 0;virtual void notifyObservers() = 0;
};// 具体主题,气象站数据
class WeatherData : public Subject 
{
private:float temperature;float humidity;float pressure;std::vector<Observer*> observers;
public:void registerObserver(Observer* o) {observers.push_back(o);}void removeObserver(Observer* o){for (std::vector<Observer*>::iterator it = observers.begin(); it!= observers.end(); ++it){if (*it == o){observers.erase(it);break;}}}void notifyObservers(){for (std::vector<Observer*>::iterator it = observers.begin(); it!= observers.end(); ++it){(*it)->update(temperature, humidity, pressure);}}void setMeasurements(float temperature, float humidity, float pressure){this->temperature = temperature;this->humidity = humidity;this->pressure = pressure;notifyObservers();}
};// 具体观察者,例如手机客户端显示天气数据
class MobileApp : public Observer
{
private:float temperature;float humidity;float pressure;
public:void update(float temperature, float humidity, float pressure){this->temperature = temperature;this->humidity = humidity;this->pressure = pressure;display();}void display(){std::cout << "Mobile App: Temperature = " << temperature << "°C, Humidity = " << humidity << "%, Pressure = " << pressure << "hPa" << std::endl;}
};// 另一个具体观察者,网页端显示天气数据
class WebPage : public Observer
{
private:float temperature;float humidity;float pressure;
public:void update(float temperature, float humidity, float pressure){this->temperature = temperature;this->humidity = humidity;this->pressure = pressure;showData();}void showData() {std::cout << "Web Page: Temperature = " << temperature << "°C, Humidity = " << humidity << "%, Pressure = " << pressure << "hPa" << std::endl;}
};int main() 
{WeatherData weatherData;MobileApp mobileApp;WebPage webPage;weatherData.registerObserver(&mobileApp);weatherData.registerObserver(&webPage);weatherData.setMeasurements(25.0, 60.0, 1013.0);weatherData.removeObserver(&mobileApp);weatherData.setMeasurements(26.0, 55.0, 1015.0);return 0;
}

在上述代码中:
Observer是抽象观察者,规定了update方法接口,用于接收主题状态变化的通知并处理。
Subject是抽象主题,定义了注册、移除观察者以及通知观察者等相关接口。
WeatherData作为具体主题,管理着观察者列表,当调用setMeasurements方法改变内部天气数据状态时,会通过notifyObservers方法通知所有已注册的观察者。
MobileApp和WebPage是具体观察者,实现了update方法,在接收到气象站(主题)的通知后,各自通过不同的显示方法(display和showData)来展示更新后的天气数据。在main函数中演示了观察者的注册、主题状态更新通知以及观察者移除等操作流程,体现了观察者模式的基本应用场景。

C++代码示例2

//观察者
#include<iostream>
#include<list>
using namespace std;
//观察者模式(Observer),又叫发布-订阅模式(Publish/Subscribe),定义对象间一种一对多的依赖关系,
//使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新class USER
{
public:virtual void Update(){}
};
class USERLI:public USER
{void Update(){cout<<"我是小李,我去看华为博客了"<<endl;}
};class USERWANG:public USER
{void Update(){cout<<"我是小王,我去看华为博客了"<<endl;}
};class BLOG
{
public:list<USER*> m_list;//保存观察者(就是关注我博客的用户)//记录观察者void AddUser(USER *p_user){m_list.push_back(p_user);}void ReMoveUser(USER *p_user){m_list.remove(p_user);}//开始通知所有我的观察者void NotiFy(){list<USER*>::iterator itr = m_list.begin();for(;itr!=m_list.end();++itr){(*itr)->Update();}}
};//华为博客
class BLOG_HUAWEI:public BLOG
{
public:void WriteBlogOk(){NotiFy();}
};int main()
{BLOG_HUAWEI huawei;USERLI *xiaoli = new USERLI();USERWANG *xiaowang =new USERWANG();huawei.AddUser(xiaowang);huawei.AddUser(xiaoli);huawei.WriteBlogOk();//这个时间点触发通知return 0;
}

相关文章:

重温设计模式--观察者模式

文章目录 观察者模式&#xff08;Observer Pattern&#xff09;概述观察者模式UML图作用&#xff1a;实现对象间的解耦支持一对多的依赖关系易于维护和扩展 观察者模式的结构抽象主题&#xff08;Subject&#xff09;&#xff1a;具体主题&#xff08;Concrete Subject&#xf…...

vulnhub靶场——Log4j2

第一步:搭建靶场环境 #开启环境 cd vulhub/log4j/CVE-2021-44228 docker-compose up -d 来到网站首页 第二步:搭建一个dnslog平台上获取我们注入的效果 第三步:发现 /solr/admin/cores?action 这里有个参数可以传 我们可以看到留下了访问记录并且前面的参数被执行后给我们回…...

Vue3中使用resolve进行路径别名设置

Vue3中使用resolve进行路径别名设置 使用Vite初始化Vue3项目工程请参考文章&#xff1a;Vite创建Vue3工程并引入ElementPlus&#xff08;图文详细&#xff09; 1.使用~路径别名替换根目录&#xff0c;使用路径别名替换src目录 在vite.config.js配置文件下添加如下配置 impo…...

Linux 添加磁盘

1、编辑虚拟机添加磁盘 然后开启虚拟机 选项如下&#xff1a; DOS (MBR) a 切换可引导标志 b 编辑嵌套的 BSD 磁盘标签 c 切换 DOS 兼容标志 通用 d 删除一个分区 F 列出未分配的空闲空间 l 列出已知的分区类型 n 添加一个新分区 p 打印分区表 t 更改分区类…...

集成 jacoco 插件,查看单元测试覆盖率

文章目录 前言集成 jacoco 插件&#xff0c;查看单元测试覆盖率1. 添加pom2. 配置完成、执行扫描3. 执行结果4. 单元测试报告 前言 如果您觉得有用的话&#xff0c;记得给博主点个赞&#xff0c;评论&#xff0c;收藏一键三连啊&#xff0c;写作不易啊^ _ ^。   而且听说点赞…...

MySQL purged gtid是如何生成和维护的

目录 1. GTID的基本概念2. GTID的生成3. GTID的清除3.1 手动清除二进制日志3.2 自动清除二进制日志3.3 重置主库 在MySQL中&#xff0c;gtid_purged表示已清除的GTID集合。 gtid_purged的生成和维护过程如下&#xff1a; 1. GTID的基本概念 GTID&#xff08;Global Transact…...

[创业之路-206]:《华为战略管理法-DSTE实战体系》- 6-关键成功因素法CSF

目录 一、概述 1、定义与起源 2、关键成功因素的定义 3、关键成功因素的来源 4、关键成功因素的确认方法 5、关键成功因素法的步骤 6、关键成功因素法的应用 7、关键成功因素法的优势与局限性 二、 关键成功因素法CSF的应用 1、企业战略管理 2、项目管理 3、绩效管…...

[Unity]【图形渲染】【游戏开发】Shader数学基础4-更多矢量运算

在计算机图形学和着色器编程中,矢量运算是核心的数学工具之一。矢量用于描述空间中的位置、方向、速度等各种物理量,并在图形变换、光照计算、纹理映射等方面起着至关重要的作用。本篇文章将详细讲解矢量和标量之间的乘法与除法、矢量的加法与减法、矢量的模与单位矢量、点积…...

目标检测——基于yolov8和pyqt的螺栓松动检测系统

目录 1.项目克隆和环境配置1.1 我这里使用的是v8.0.6版本1.2 项目代码结构介绍 2.数据集介绍2.1 数据集采集2.2采集结果介绍 3.模型训练4.pyqt界面设计4.1 界面内容介绍4.2 界面实现 5.操作中的逻辑实现5.1 图片检测5.2 文件夹检测5.3 视频检测和摄像头检测 6. 效果展示 1.项目…...

【Java数据结构】LinkedList

认识LinkedList LinkedList就是一个链表&#xff0c;它也是实现List接口的一个类。LinkedList就是通过next引用将所有的结点链接起来&#xff0c;所以不需要数组。LinkedList也是以泛型的方法实现的&#xff0c;所以使用这个类都需要实例化对象。 链表分为很多种&#xff0c;比…...

图像处理-Ch4-频率域处理

Ch4 频率域处理(Image Enhancement in Frequency Domain) FT &#xff1a;将信号表示成各种频率的正弦信号的线性组合。 频谱&#xff1a; ∣ F ( u , v ) ∣ [ R 2 ( u , v ) I 2 ( u , v ) ] 1 2 |F(u, v)| \left[ R^2(u, v) I^2(u, v) \right]^{\frac{1}{2}} ∣F(u,v)…...

WPS工具栏灰色怎么办

WPS离线不登录&#xff0c;开启工具栏等相关功能 当你在使用WPS的过程中&#xff0c;若因网络问题或其他特殊原因&#xff0c;导致无法登录使用WPS时&#xff0c;可根据以下步骤开启离线兼容模式&#xff0c;开启此模式后&#xff0c;可在未登录的状态下&#xff0c;激活并使用…...

渐开线齿轮和摆线齿轮有什么区别?

摆线齿形与渐开线齿形的区别 虽然在比对这两种齿形&#xff0c;但有一个事情希望大家注意&#xff1a;渐开线齿轮只是摆线齿轮的一个特例。 &#xff08;1&#xff09;摆线齿形的压力角在啮合开始时最大&#xff0c;在齿节点减小到零&#xff0c;在啮合结束时再次增大到最大…...

vulnhub靶场-matrix-breakout-2-morpheus攻略(截止至获取shell)

扫描出ip为192.168.121.161 访问该ip&#xff0c;发现只是一个静态页面什么也没有 使用dir dirsearch 御剑都只能扫描到/robots.txt /server-status 两个页面&#xff0c;前者提示我们什么也没有&#xff0c;后面两个没有权限访问 扫描端口&#xff0c;存在81端口 访问&#x…...

应用高次、有理代数式为AI生成亚对称图像

原创&#xff1a;daode1212(daode3056) 本文定义不完全对称的图像叫亚对称图像&#xff0c;因为全对称的太过机械&#xff0c;不符合人工的特点&#xff0c;本人基于二元高次的有理式&#xff0c;生成时引入N个随机数分A,B两个组&#xff0c;再通过指针对画布所有像素高速扫描生…...

潜在狄利克雷分配LDA 算法深度解析

引言 潜在狄利克雷分配&#xff08;Latent Dirichlet Allocation, LDA&#xff09;是一种广泛应用于文本挖掘和信息检索领域的主题模型。它能够从文档集合中自动发现隐藏的主题结构&#xff0c;为理解大规模文本数据提供了强有力的工具。本文将着重讲解 LDA 的核心理论&#x…...

[x86 ubuntu22.04]双触摸屏的触摸事件都响应在同一个触摸屏上

1 问题描述 CPU&#xff1a;G6900E OS&#xff1a;ubuntu22.04 Kernel&#xff1a;6.8.0-49-generic 系统下有两个一样的 edp 触摸屏&#xff0c;两个触摸屏的触摸事件都响应在同一个 edp 屏幕上。 2 解决过程 使用“xinput”命令查看输入设备&#xff0c;可以看到只有一个 to…...

重温设计模式--代理模式

文章目录 定义UML图代理模式主要有以下几种常见类型&#xff1a;代理模式涉及的主要角色有&#xff1a;C 代码示例 定义 代理模式&#xff08;Proxy Pattern&#xff09;属于结构型设计模式&#xff0c;它为其他对象提供一种代理以控制对这个对象的访问。 通过引入代理对象&am…...

一些elasticsearch重要概念与配置参数

ES 是在 lucene 的基础上进行研发的&#xff0c;隐藏了 lucene 的复杂性&#xff0c;提供简单易用的 RESTful Api接口。ES 的分片相当于 lucene 的索引。 Node 节点的几种部署实例 实例一: 只用于数据存储和数据查询&#xff0c;降低其资源消耗率 node.master: false node.da…...

leetcode 面试经典 150 题:螺旋矩阵

链接螺旋矩阵题序号54题型二维数组&#xff08;矩阵&#xff09;解题方法模拟路径法难度中等熟练度✅✅✅ 题目 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3…...

JAVA AOP简单实践(基于SpringBoot)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…...

java agent的使用【通俗易懂版】

一、静态代理Agent 1&#xff0e;生成Agent的jar包 &#xff08;1&#xff09;创建Agent项目&#xff0c;引入javassist.jar包 &#xff08;2&#xff09;编写premain方法 import java.lang.instrument.Instrumentation;public class Agent1 {public static void premain(Stri…...

大模型学习指南

随着人工智能的迅猛发展&#xff0c;大模型成为了技术前沿的璀璨明星。踏入大模型学习领域&#xff0c;需要在多个关键方面下功夫。 扎实的数学功底是基石。线性代数为理解多维数据、矩阵运算提供支撑&#xff0c;像大模型中权重矩阵的处理就离不开它&#xff1b;概率论与数理…...

单片机:实现定时器中断(数码管读秒+LED闪烁)(附带源码)

单片机实现定时器中断&#xff1a;数码管读秒与LED闪烁 在单片机项目中&#xff0c;定时器中断是一个常见的应用&#xff0c;用于实现定时任务&#xff0c;例如定时更新显示或控制周期性事件。本文将介绍如何使用定时器中断实现数码管读秒和LED闪烁功能。通过使用定时器中断&a…...

STM32单片机芯片与内部33 ADC 单通道连续DMA

目录 一、ADC DMA配置——标准库 1、ADC配置 2、DMA配置 二、ADC DMA配置——HAL库 1、ADC配置 2、DMA配置 三、用户侧 1、DMA开关 &#xff08;1&#xff09;、标准库 &#xff08;2&#xff09;、HAL库 2、DMA乒乓 &#xff08;1&#xff09;、标准库 &#xff…...

【0376】Postgres内核 分配 last safe MultiXactId

上一篇: 【0375】Postgres内核 XLOG 之 设置下一个待分配 MultiXactId 和 offset 文章目录 1. 最后一个安全的 MultiXactId1.1 计算 multi wrap limit1.2 计算 multi stop limit1.3 计算 multi warn limit1.4 计算 multi vacuum limit2. 初始化 MultiXactState 成员3. 完成 mu…...

php时间strtotime函数引发的问题 时间判断出错

在 PHP 中&#xff0c;strtotime 函数能处理的最大时间范围取决于您的系统和 PHP 版本。 一般来说&#xff0c;它可以处理的时间范围从 1901 年 12 月 13 日到 2038 年 1 月 19 日。超过这个范围可能会导致不可预测的结果或错误。 如果您需要处理更大范围的时间&#xff0c;可能…...

Kibana:LINUX_X86_64 和 DEB_X86_64两种可选下载方式的区别

最近需要在vm&#xff08;操作系统是 Ubuntu 22.04.4 LTS&#xff0c;代号 Jammy。这是一个基于 x86_64 架构的 Linux 发行版&#xff09;上安装一个7.17.8版本的Kibana&#xff0c;并且不采用docker方式。 在下载的时候发现有以下两个选项&#xff0c;分别是 LINUX_X86_64 和 …...

【LeetCode每日一题】 LeetCode 151.反转字符串中的单词

LeetCode 151.反转字符串中的单词 题目描述 给你一个字符串 s &#xff0c;请你反转字符串中单词的顺序。 单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。 返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。 注意&#xff1a;…...

gitlab克隆仓库报错fatal: unable to access ‘仓库地址xxxxxxxx‘

首次克隆仓库&#xff0c;失效了&#xff0c;上网查方法&#xff0c;都说是网络代理的问题&#xff0c;各种清理网络代理后都无效&#xff0c;去问同事&#xff1a; 先前都是直接复制的网页url当做远端url&#xff0c;或者点击按钮‘使用http克隆’ 这次对于我来说有效的远端u…...