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

文章目录

  • 观察者模式(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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

正则表达式优化之算法和效率优化

正则表达式优化之算法和效率优化 前言 正则表达式是处理文本匹配的强大工具&#xff0c;但在实际应用中&#xff0c;如果不加以优化&#xff0c;可能会导致性能问题或匹配结果不精确。 本文将分三篇从表达式结构、算法效率和实际应用场景三个方面. 深入探讨如何优化正则表达…

workman服务端开发模式-应用开发-gateway长链接端工作原理

一、长链接的工作原理 Register类其实也是基于基础的Worker开发的。Gateway进程和BusinessWorker进程启动后分别向Register进程注册自己的通讯地址&#xff0c;Gateway进程和BusinessWorker通过Register进程得到通讯地址后&#xff0c;就可以建立起连接并通讯了。而Gateway进程…

排序算法 (插入,选择,冒泡,希尔,快速,归并,堆排序)

排序:经常在算法题中作为一个前置操作,为了之后的贪心or else做个铺垫,虽然我们经常都只是调用个sort,但是了解一些排序算法可以扩充下知识库 排序的分类: 从存储设备角度&#xff1a; ✓ 内排序&#xff1a;在排序过程中所有数据元素都在内存中&#xff1b; ✓ 外排序&a…

云途领航:现代应用架构助力企业转型新篇

在数字化转型的浪潮中&#xff0c;现代应用架构为企业带来了灵活性、效率和创新能力。各类服务模型相继出现&#xff0c;为企业提供了强有力的支持&#xff0c;助力其顺利转型。随着技术的快速发展&#xff0c;企业面临的挑战和机遇也在不断演变&#xff0c;这促使它们必须重新…

【IMU:视觉惯性SLAM系统】

视觉惯性SLAM系统简介 相机&#xff08;单目/双目/RGBD)与IMU结合起来就是视觉惯性&#xff0c;通常以单目/双目IMU为主。 IMU里面有个小芯片可以测量角速度与加速度&#xff0c;可分为6轴(6个自由度)和9轴&#xff08;9个自由度&#xff09;IMU&#xff0c;具体的关于IMU的介…

面试题整理3----nc命令的常见用法

面试题整理3----nc命令的常见用法 1. NC是什么2. NC的常用参数2.1 开启指定端口TCP监听(-l小写的L)2.2 测试端口是否能访问(-v)2.3 开启指定端口UDP监听(-u)2.4 端口扫描(-z)2.5 指定超时时间(-w)2.6 指定本地端口号连接(-p)2.7 指定的命令(-e) 1. NC是什么 nc&#xff08;Net…

ubuntu 如何重装你的apt【apt-get报错: symbol lookup error/undefined symbol】

副标题:解决error:apt-get: symbol lookup error: /lib/x86_64-linux-gnu/libapt-private.so.0.0: undefined symbol: _ZNK13pkgTagSection7FindULLENS_3KeyERKy, version APTPKG_6.0 文章目录 问题描述报错分析解决方案:重装你的apt1、查看你的ubuntu版本2、下载适配你的ap…

解决:excel鼠标滚动幅度太大如何调节?

在excel里为什么滚动一次跳过很多行呢&#xff1f;很不方便。。。 1. 问题&#xff1a; 一开始单元格从第1行开始&#xff1a; 鼠标轻轻滚动一下后&#xff0c;直接跳到第4行&#xff1a; 鼠标在word和浏览器里都是好好的。在excel里为什么不是滚动一次跳过一行呢&#xff…

VMWare 的克隆操作

零、碎碎念 VMWare 的这个克隆操作很简单&#xff0c;单拎出来成贴的目的是方便后续使用。 一、操作步骤 1.1、在“源”服务器上点右键&#xff0c;选择“管理--克隆” 1.2、选择“虚拟机的当前状态”为基础制作克隆&#xff0c;如下图所示&#xff0c;然后点击“下一页” 1.3、…

ARM 处理器平台 Ethernet Compliance 测试流程示例

By Toradex秦海 1). 简介 为了保证基于IEEE 802.3 协议设计的以太网设备接口可以互相兼容互联互通&#xff0c;需要进行 Ethernet Compliance 一致性测试&#xff0c;相关的技术原理说明请参考如下文章&#xff0c;本文就不赘述&#xff0c;主要展示基于 NXP i.MX8M Mini ARM…

门控循环单元(GRU):深度学习中的序列数据处理利器

目录 ​编辑 引言 GRU的诞生背景 GRU的核心机制 GRU的计算过程 GRU的数学公式 GRU的应用领域 代码示例&#xff1a;PyTorch中的GRU GRU与LSTM的比较 参数比较 GRU的技术发展 BiGRU&#xff08;双向GRU&#xff09; BiGRU的实现示例 GRU与CNN的结合 GRU的应用案例…

C#都可以找哪些工作?

在国内学习C#&#xff0c;可以找的工作主要是以下4个&#xff1a; 1、游戏开发 需要学习C#编程、Unity引擎操作、游戏设计和3D图形处理等。 2、PC桌面应用开发 需要学习C#编程、WinForm框架/WPF框架、MVVM设计模式和UI/UX设计等。 3、Web开发 需要学习C#编程、ASP.NET框架…

视频直播点播平台EasyDSS与无人机技术的森林防火融合应用

随着科技的飞速发展&#xff0c;无人机技术以其独特的优势在各个领域得到了广泛应用&#xff0c;特别是在森林防火这一关键领域&#xff0c;EasyDSS视频平台与无人机技术的融合应用更是为传统森林防火手段带来很大的变化。 一、无人机技术在森林防火中的优势 ‌1、快速响应与高…

【编译原理】编译原理知识点汇总·词法分析器(正则式到NFA、NFA到DFA、DFA最小化)

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;编译原理_十二月的猫的博客-CSDN博客 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 1. 前言 2. …

SAP抓取外部https报错SSL handshake处理方法

一、问题描述 SAP执行报表抓取https第三方数据,数据获取失败。 报错消息: SSL handshake with XXX.COM:449 failed: SSSLERR_SSL_READ (-58)#SAPCRYPTO:SSL_read() failed##SapSSLSessionStartNB()==SSSLERR_SSL_READ# SSL:SSL_read() failed (536875120/0x20001070)# …

java栈

前言 java实现数据结构栈&#xff1a;用顺序表存储的栈和数组存储的栈。 本文源代码网址&#xff1a;https://gitee.com/zfranklin/java/tree/master/dataStructure/src/com/njupt/stack https://gitee.com/zfranklin/java/tree/master/dataStructure/src/com/njupt/stack 栈…

「Mac畅玩鸿蒙与硬件45」UI互动应用篇22 - 评分统计工具

本篇将带你实现一个评分统计工具&#xff0c;用户可以对多个选项进行评分。应用会实时更新每个选项的评分结果&#xff0c;并统计平均分。这一功能适合用于问卷调查或评分统计的场景。 关键词 UI互动应用评分统计状态管理数据处理多目标评分 一、功能说明 评分统计工具允许用…

使用 AI 辅助开发一个开源 IP 信息查询工具:一

本文将分享如何借助当下流行的 AI 工具,一步步完成一个开源项目的开发。 写在前面 在写代码时&#xff0c;总是会遇到一些有趣的机缘巧合。前几天&#xff0c;我在翻看自己之前的开源项目时&#xff0c;又看到了 DDNS 相关的讨论。虽然在 2021 年我写过两篇相对详细的教程&am…

高效处理PDF文件的终极工具:构建一个多功能PDF转换器

在日常工作中&#xff0c;处理PDF文件几乎是每个人都不可避免的任务。无论是从PDF中提取数据、合并多个PDF文件&#xff0c;还是处理文件中的敏感信息和图像&#xff0c;PDF文件的处理都可能成为繁琐且耗时的工作。如果你是数据分析师、工程师&#xff0c;或者从事文档管理的工…

差分矩阵(Difference Matrix)与累计和矩阵(Running Sum Matrix)的概念与应用:中英双语

本文是学习这本书的笔记: https://web.stanford.edu/~boyd/vmls/ 差分矩阵&#xff08;Difference Matrix&#xff09;与累计和矩阵&#xff08;Running Sum Matrix&#xff09;的概念与应用 在线性代数和信号处理等领域中&#xff0c;矩阵运算常被用来表示和计算各种数据变换…