观察者模式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,一经查实,立即删除!

相关文章

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

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

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

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

系统下载地址

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

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

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

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

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

学习路线

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

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

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

WPF 实现调用本机摄像头~

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

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

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

C++之‘nullptr’ was not declared in this scope

在vim里面写了一个简单cpp文件,为了避免野指针,需要指针初始化 char *p2 = nullptr 1、编译时报错如下 2、解决办法 编译加上 g++ -std=gnu++0x int.cpp -o int 3、C里面的null和C++里面的nullptr、NULL介绍 NULL在C++中的定义 /* Define NULL pointer value */ #ifndef …

想说爱你不容易 | 使用最小 WEB API 实现文件上传

前言在 .NET 6 之前&#xff0c;实现文件上传功能十分简单&#xff1a;[HttpPost("upload")] public async Task<IActionResult> Upload(IFormFile file) {//对file执行操作return Ok(file.FileName); }但是&#xff0c;当使用 .NET 6 的最小 WEB API 来实现相…

Android下载文件

2019独角兽企业重金招聘Python工程师标准>>> package com.test;import java.io.File;import java.io.FileOutputStream;import java.io.InputStream;import java.net.URL;import java.net.URLConnection;import android.app.Activity;import android.content.Intent…

C++之operator关键字(重载操作符) 使用总结

operator是C++的关键字,它和运算符一起使用,表示一个运算符函数, 一、为什么使用操作符重载 简单的说我们基本数据比如int float 都可以比较大小 有>、<、=,但是对象需要比较大小怎么办,我们也可以用>、<、=,只不过我们需要一个通用的规范比较对象的属性…

#HTTP协议学习# (七)cookie

本文转自&#xff1a;http://www.cnblogs.com/TankXiao/archive/2012/12/12/2794160.html Cookie是HTTP协议中非常重要的东西&#xff0c; 之前拜读了Fish Li 写的【细说Cookie】&#xff0c; 让我学到了很多东西。Fish的这篇文章写得太经典了。 所以我这篇文章就没有太多内容了…

C#中的类型~存储~变量

欢迎您成为我的读者&#xff0c;希望这篇文章能给你一些帮助。前言今天在群里看到朋友讨论把粉丝称为读者&#xff0c;这让我内心特别激动。以前我还是比较关注自己的文章阅读量&#xff0c;有没有人转发&#xff0c;今天新增多少个关注。而现在&#xff0c;我的关注点变了&…

C++之typename

1、typename和class 在模板前,typename和class没有区别 template<typename T> class A; template<class T> class A;typename和class对编译器而言却是不同的东西 2、声明一个类型 看下面的代码 我们编译下结果如下 编译器不知道T::const_iterator是个类型。如果…

mooc数据结构与算法python版期末考试_数据结构与算法Python版-中国大学mooc-试题题目及答案...

数据结构与算法Python版-中国大学mooc-试题题目及答案更多相关问题婴儿出生一两天后就有笑的反应&#xff0c;这种笑的反应属于()。【判断题】填制原始凭证&#xff0c;汉字大写金额数字一律用正楷或草书书写&#xff0c;汉字大写金额数字到元位或角位为止的&#xff0c;后面必…

使用 NetCoreBeauty 优化 .NET CORE 独立部署目录结构

在将一个 .NET CORE \ .NET 5.0 \ .NET 6.0 程序进行独立部署发布时&#xff0c;会在发布目录产生很多系统类库&#xff0c;导致目录非常不简洁。这给寻找入口程序造成了困难&#xff0c;特别是路遥工具箱这种绿色软件&#xff0c;不会在开始菜单、系统桌面创建快捷方式&#x…

ios之最简单的程序

1、构建学生对象并且打印相关信息 代码&#xff1a;#import <UIKit/UIKit.h> #import "AppDelegate.h"interface Student : NSObject //变量 property NSString *name; property int age; property float score;//method -(void)show;endimplementation Studen…

网站前端_EasyUI.基础入门.0009.使用EasyUI Layout组件的最佳姿势?

1. 基础布局<div id"l" class"easyui-layout" data-options"width:500,height:250"><div data-options"region:north,title:north,height:50"></div><div data-options"region:west,title:west,width:100&q…