观察者模式VS发布-订阅模式

4c9e6e42c5123cbacb0c631ae5f63519.gif

前言

观察者模式的大名,想必各位看官早已有所耳闻。从我们现实生活来说,微信公众号订阅、医院挂号叫号等都属于它的实际应用。在程序世界中,它是一种用于将代码解耦的设计模式,如果你想掌握并理解这种设计模式,今天就和我一起来探究它的奥秘之处吧!

b9df9de2af5675f3f3bf1090228009f6.gif

观察者模式

在前文讲述事件机制时,我们其实已经提到了观察者模式。观察者模式事实上实现了一种通讯机制,也就是观察目标对观察者进行通知的机制。在基于低耦合的设计前提下,观察者无需直接调用观察目标的内部方法或属性获取通知,而是使用“订阅”的方式获取通知,大体的流程图如下:

086239278cda6c54aa98ef06548088d9.png

结合实际开发例子来说,在C#中我们只需要定义相应的委托和事件,即可实现观察者模式的使用,详细使用方法可以参考我之前的文章内容:再谈C#中的委托和事件,在此不再赘述。

但在其他语言中,例如Java,本身未提供类似委托或事件的机制进行回调,因此在实现方面会略微繁琐一些,相关类图如下:

14ad559fad2eef5ee61fd3f5696762a3.png

在这种实现方式中,我们需要对观察目标,也就是发布主题进行一个抽象,即图中的Subject,用于提供保存观察者的集合(图中的ArrayList),以及对观察者的增加或删除的方法。而在具体主题(图中的ConcreteSubject)中,包含了状态属性,以及状态变化的方法,在自身发生变化时,会调用notifyObserver方法进行通知。

在观察者的实现中,也存在抽象观察者(Observer)和具体观察者(ConcreteObserver)两种角色。前者一般定义一个接口,用于在接收到变化通知时,对自身进行更新。而后者会实现具体的update方法,类似C#中我们订阅事件之后触发的回调方法。

以上就是我们在两种语言中分别实现观察者模式的方式,正如软件工程强调的“没有银弹”的说法,观察者模式虽然解决了很多问题,但也存在部分缺点,主要内容如下:

1、观察者数量很多时,逐个通知会非常耗时。正如我们上述实现,存在一个ArrayList来保存所有的观察者,如果这个ArrayList中的元素足够大,那么在通知时程序的执行效率势必是很低下的。

2、如果观察目标与观察者之间存在循环依赖时,观察者模式会触发双方的循环调用,导致系统崩溃。

3、缺乏相应的机制通知观察者观察目标是如何发生变化的,观察者仅仅是得知观察目标发生了变化。当然这一点也不是绝对的,我们在程序实现时可以通过传递参数或者对象的方式去“告知”观察者,观察目标发生了哪些变化。

我们在讲述观察者模式时,反复提到了“主题”和“订阅”的概念。从概念上理解而言,似乎观察者模式,就是发布-订阅模式,那么两者之间究竟有没有区别呢?我们一起进入下一章节来继续探究。

cc6df6ae9f8a9759a06d3c6186099e3c.gif

发布订阅模式

事实上,发布订阅模式,和观察者模式是有区别的。回到我们最开始的例子,微信公众号的订阅,看似是直接关注了公众号,实质上,在关注和推送的两种行为中,都是要通过“微信公众平台”这个第三方来实现的。看到这里,聪明的各位应该可以理解到发布订阅模式的不同之处,没错,发布订阅模式是在观察者模式的基础上,加入了“事件中心”的概念:

3fce2461b1719bc08044ba089aaed882.png

通过事件中心,发布者和订阅者进行了进一步的解耦,发布者无需关心订阅者的订阅情况,而是直接发布主题到事件中心即可。而订阅者也无需关心发布者自身的情况,甚至不知道发布者是何人,只需要接收事件中心的通知即可。

发布订阅模式在目前的各种消息中间件中应用非常广泛,如常见的RabbitMQ,kafka等,发布者发布主题,消费者订阅对应的主题对发布的消息进行消费,相信大家对这些概念并不陌生。

9db712decdeb2d17da1495cda6fcf016.gif

小结

至此,我们今天要探究的主题就暂时告一段落。观察者模式与发布订阅模式如此相似,但又有所不同,在我们理清各自的概念和实现方式后,又会发现在我们日常的应用中这两种模式无所不在。

设计模式本身就是一些优秀的前辈在开发过程中对一些最佳实践和方法论做出的沉淀和总结,所以大家在提到这些内容时,不要先入为主的认为这些东西只是停留在概念阶段,无法落地实践。而是需要结合自己的实际工作,仔细思考设计模式该如何应用,如何选择合适的设计模式,解决自己遇到的问题。当然,永远没有最优的方案,滥用设计模式只会大大降低程序的可读性,对后续维护造成困难。活学活用,在这里祝愿大家可以和我一起学习,共同进步和成长,我们下期再见!

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

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

相关文章

mysql insert replace_mysql 操作总结 INSERT和REPLACE

--他人总结的用于操作数据库的SQL一般分为两种,一种是查询语句,也就是我们所说的SELECT语句,另外一种就是更新语句,也叫做数据操作语句。言外之意,就是对数据进行修改。在标准的SQL中有3个语句,它们是INSER…

C++之‘malloc’ was not declared in this scope和invalid conversion from ‘void*’ to ‘char*’

1、错误一 ‘malloc’ was not declared in this scope 2解决 加上头文件文件<stdlib.h> 3、错误二 invalid conversion from ‘void*’ to ‘char*’ 4、解决 在malloc函数前面加上强转类型(char *)

Python 运算符

Python语言支持以下类型的运算符: 算术运算符比较&#xff08;关系&#xff09;运算符赋值运算符逻辑运算符位运算符成员运算符身份运算符运算符优先级Python算术运算符 以下假设变量a为10&#xff0c;变量b为20&#xff1a; 运算符描述实例加 - 两个对象相加a b 输出结果 30-…

Kubernetes 集群和应用监控方案的设计与实践

目录Kubernetes 监控监控对象Prometheus指标实践节点监控部署 Prometheus部署 Kube State Metrics部署 Grafana应用如何接入 Prometheus 和 Grafana告警Kubernetes 监控当你的应用部署到 Kubenetes 后&#xff0c;你很难看到容器内部发生了什么&#xff0c;一旦容器死掉&#x…

全局照明算法基础——从辐射亮度到渲染方程

全局照明&#xff08;Global Illumination&#xff09;问题上已经有很多著名的算法&#xff0c;如路径追踪&#xff08;Path Tracing&#xff09;&#xff0c;辐照度&#xff08;Radiosity&#xff09;等。绝大部分书籍/教材都直接介绍了做法&#xff0c;在理论方面有所欠缺&am…

mysql 开发规范_专业级的MySQL开发设计规范及SQL编写规范

在团队开发过程中为了项目的稳定&#xff0c;代码的高效&#xff0c;管理的便捷制定内部种开发设计规范是必不可少的&#xff0c;这里分享一份我们定义MySQL开发设计规范包括表设计规范&#xff0c;字段设计规范&#xff0c;SQL编写规范数据库对象命名规范数据库对象命名规范的…

C++之explicit关键字使用总结

1、explicit关键字介绍 C++中的explicit关键字只能用于修饰只有一个参数的类构造函数, 它的作用是表明该构造函数是显示的, 而非隐式的, 关键字是implicit, 意思是隐藏的,类构造函数默认情况下即声明为implicit(隐式). 2、贴代码 #include <iostream> #include <stdi…

系统下载地址

系统下载地址 http://pan.baidu.com/s/1o6hVbPC 其中有xp win7和win8 32位 win7和win8 64位转载于:https://blog.51cto.com/freedom886/1403433

聊一聊DTM子事务屏障功能之SQL Server版

背景 前面写了两篇&#xff08;聊一聊如何用C#轻松完成一个SAGA分布式事务和聊一聊如何用C#轻松完成一个TCC分布式事务&#xff09;如何用 C# 基于 DTM 轻松实现 SAGA 和 TCC 的分布式事务&#xff0c;其中有一个子事务屏障的功能&#xff0c;很好的处理了空补偿、悬挂、重复请…

更为详细的Txtsetup.sif文件解释

更为详细的Txtsetup.sif文件解释;代码页定义, 以免文本安装模式下无法正常显示简体中文 (以下基本都是跟简体中文相关的, 不同语言版本的 Windows, 此处定义也不同)[nls]AnsiCodepage c_936.nls,936OemCodepage c_936.nls,936MacCodepage c_10008.nls,10008UnicodeCasetable…

C++类与const关键字

1、const成员变量 const 成员变量的用法和普通 const 变量的用法相似,只需要在声明时加上 const 关键字 const 成员函数可以使用类中的所有成员变量,但是不能修改它们的值,这种措施主要还是为了保护数据而设置的 2、const 成员函数也称为常成员函数。 常成员函数需要在声明…

Dos中转义符

遇到个问题&#xff1a; java test R<file> 11 22 按理说应该打印 R<file>1122但是&#xff0c;系统报错&#xff0c;写的是系统找不到指定文件。 是"<>"引起的&#xff0c;加上Dos转义符中"^"即可。 java test R^<file^> 11 22 测…

ORA-00257+mysql_ORA-00257错误的解决办法

author&#xff1a; headsen chendate&#xff1a; 2018-04-17 11:12:39notice&#xff1a;个人原创&#xff0c;转载请注明作者和出处&#xff0c;否则依法追击法律责任。1&#xff0c;oracle数据库正常使用中&#xff0c;突然报ora-00257的错误&#xff0c;原因是归档日志满…

可穿戴设备对企业的积极意义

在耐克裁掉该公司的FuelBand运动手环硬件部门后&#xff0c;众多媒体和肇事者即开始唱衰可穿戴设备。在这些唱衰可穿戴的人总&#xff0c;有一些人从来没有用过可穿戴设备&#xff0c;有的甚至都没有见过可穿戴设备&#xff0c;他们只是根据自己的臆想&#xff0c;过往的经验&a…

学习路线

为什么80%的码农都做不了架构师&#xff1f;>>> 一、构想 1.专门制定某领域学习路线。 2.为人们进入某领域而学习提供依据。 转载于:https://my.oschina.net/kun123/blog/838360

C++之inline函数使用总结

一、C++为什么引入inline函数? 主要目的:用它代替C语言中表达式形式的宏定义来解决程序中函数调用的效率问题。 C语言中的宏定义,它使用预处理器实现,没有了参数压栈、代码生成等一系列得到操作,因此效率很高。 但缺点如下: 预处理器符号表中的简单替换,不能进行参数…

数字图像处理技术在TWaver可视化中的应用

数字图像处理&#xff08;Digital Image Processing&#xff09;又称为计算机图像处理&#xff0c;它是指将图像信号转换成数字信号并利用计算机对其进行处理的过程。常用的图像处理方法有图像增强、复原、编码、压缩等&#xff0c;数字图像处理应用领域非常广泛。具体关于数字…

WPF 实现调用本机摄像头~

WPF开发者QQ群&#xff1a;340500857由于微信群人数太多入群请添加小编微信号yanjinhuawechat 或 W_Feng_aiQ 邀请入群需备注WPF开发者 PS&#xff1a;有更好的方式欢迎推荐。接着很久前的上一篇此项目使用了OpenCVSharp加载本地摄像头&#xff0c;多个摄像头支持切换展示&…

python process 函数_Python Process创建进程的2种方法详解

前面介绍了使用 os.fork() 函数实现多进程编程&#xff0c;该方法最明显的缺陷就是不适用于 Windows 系统。本节将介绍一种支持 Python 在 Windows 平台上创建新进程的方法。Python multiprocessing 模块提供了 Process 类&#xff0c;该类可用来在 Windows 平台上创建新进程。…

全球增长最快域名解析商Top10:中国占据四席

IDC评述网&#xff08;idcps.com&#xff09;04月29日报道&#xff1a;根据国外域名统计机构DailyChanges最新实时数据显示&#xff0c;4月27日&#xff0c;在全球增长最快的十家域名解析服务商榜单中&#xff0c;中国占据四个席位。上榜的中国域名解析商分别是&#xff1a;51D…