小侃设计模式(十八)-发布订阅模式

article/2025/10/27 3:25:42

1.概述

发布订阅模式又叫观察者模式(Observer Pattern),它是指对象之间一对多的依赖关系,每当那个特定对象改变状态时,所有依赖于它的对象都会得到通知并被自动更新,它是行为型模式的一种。观察者模式内部有一个“主题”对象和若干个“观察者”对象,“主题对象”和“观察者”对象是一对多的依赖关系,当“主题”的状态发生变化时,所有“观察者”都得到通知。本文将详述观察者模式的原理及使用方式。

2.原理及使用

2.1 原理

观察者模式UML类图如下:
在这里插入图片描述

类图中包含的核心角色有:Subject(抽象被观察者)、ConcreteSubject(具体被观察者)、Observer(抽象观察者)、ObserverA、ObserverB、ObserverC(具体观察者),详细解释如下:

Subject(抽象被观察者): 它定义了一个集合,存储所有的观察者,且对外提供添加和删除观察者的接口;
ConcreteSubject(具体被观察者):具体角色将有关状态存入具体观察者对象,当具体主题的内部状态发生改变时,会给所有注册过的观察者发送通知;
Observer(抽象观察者):观察者抽象类,它定义了一个更新接口,使得在得到主题更改时,更新自身数据;
ObserverA(具体观察者):具体观察者,实现抽象观察者定义的更新接口,以便在主题更新时更新自身的状态。

2.2 案例

小王喜欢炒股,但他是个工薪族,白天还需要上班,他又不能辞职全职炒股(因为还有老婆孩子要养),因此他想到一个好办法,找一个股神帮助自己炒股,股神会根据行情告诉你什么时候买入、什么时候卖出,股神每年会收一定费用。

分析:上述案例中,股神就是典型的被观察者,小王就是典型的观察者,一旦观察到股神给他发的信息,就执行买入卖出动作,股神负责通知小王这种观察者。编码如下:

public abstract class Observer {public String name;public StockManager stockManager;public abstract void buy(Stock stock);public abstract void sale(Stock stock);}@Data
public class Stock {/*** 股票名称*/private String name;/*** 买入或卖出数量*/private Integer num;/*** 买入或卖出价格*/private Double price;
}@Data
@NoArgsConstructor
@AllArgsConstructor
public class StockManager {private List<Observer> lists = new ArrayList<>();public StockManager(String name) {this.name = name;}private String name;private Stock stock;public void notifyAllObserversBuy() {lists.forEach(list -> {System.out.println("通知:" + list.name);list.buy(stock);});}public void notifyAllObserversSale() {lists.forEach(list -> {System.out.println("通知:" + list.name);list.sale(stock);});}public void add(Observer observer) {lists.add(observer);System.out.println("添加新的投资客户:" + observer.name);}public void remove(Observer observer) {lists.remove(observer);System.out.println("删除老的投资客户:" + observer.name);}}public class WangObserver extends Observer {public WangObserver(StockManager stockManager, String name) {this.stockManager = stockManager;this.name = name;}@Overridepublic void buy(Stock stock) {System.out.println(name + "购买股票:" + stock.getName() + ",成交价格:" + stock.getPrice() + ",成交数量:" + stock.getNum());}@Overridepublic void sale(Stock stock) {System.out.println(name + "卖出股票:" + stock.getName() + ",成交价格:" + stock.getPrice() + ",成交数量:" + stock.getNum());}
}public class ZhangObserver extends Observer {public ZhangObserver(StockManager stockManager, String name) {this.stockManager = stockManager;this.name = name;}@Overridepublic void buy(Stock stock) {System.out.println(name + "购买股票:" + stock.getName() + ",成交价格:" + stock.getPrice() + ",成交数量:" + stock.getNum());}@Overridepublic void sale(Stock stock) {System.out.println(name + "卖出股票:" + stock.getName() + ",成交价格:" + stock.getPrice() + ",成交数量:" + stock.getNum());}
}public class Client {public static void main(String[] args) {StockManager stockManager = new StockManager("巴菲特");ZhangObserver zhangObserver = new ZhangObserver(stockManager, "小张");WangObserver wangObserver = new WangObserver(stockManager, "小王");stockManager.add(zhangObserver);stockManager.add(wangObserver);Stock stock = new Stock();stock.setName("贵州茅台");stock.setNum(1000);stock.setPrice(1589.0);stockManager.setStock(stock);stockManager.notifyAllObserversBuy();System.out.println("-------------------------");stock.setPrice(1899.0);stockManager.notifyAllObserversSale();}
}

运行结果如下:
在这里插入图片描述
严格意义上来说,观察者模式与发布订阅模式还有一些区别,观察者模式之间的发布者与订阅者是双向关联的,如下图所示:
在这里插入图片描述

发布订阅模式中的发布者与订阅者的关系如下图所示:

在这里插入图片描述
这里多了一个事件中心,负责存放事件和订阅者关系,完全解耦了发布者和订阅者。发布订阅模式是观察者模式的一种,但是又有部分区别:

1.观察者模式中,发布者与订阅者直接关联,发布者维护观察者列表,发布者状态变更通知订阅者;在发布-订阅模式中,订阅者与发布者相互不了解,通过事件中心进行通信;
2.耦合性方面,发布订阅者中发布者与订阅者完全松耦合;
3.观察者模式主要是以同步的方式来发送消息,发布订阅者一般以异步的方式来实现。

2.3 观察者在JDK源码中的应用

JDK源码中有个Observable类,它就相当于一个Subject,实现了核心方法,包括addObserver()、deleteObserver()、notifyObserver()等,JDK源码中的Observer接口,就是一个订阅者接口,代码如下:
在这里插入图片描述
在这里插入图片描述

2.4 观察者的优点与缺点

2.4.1 优点

1.发布者与观察者是抽象耦合的,
2.发布者和订阅者之间有一套完整的信息发送机制;

2.4.2 缺点

1.观察者与被观察者之间之间关联;
2.若观察者通知出现异常,则可能造成消息发送奔溃;

3.小结

1.观察者模式适用于对象状态发生变化,与之相关的对象需要收到通知并更新自身;
2.观察者模式需要考虑消息异步发送,提升容错率。

4.参考文献

1.《设计模式之禅》-秦小波著
2.《大话设计模式》-程杰著
3.https://www.bilibili.com/video/BV1G4411c7N4-尚硅谷设计模式
4.https://www.runoob.com/design-pattern/observer-pattern.html


http://chatgpt.dhexx.cn/article/Qt5ShWVf.shtml

相关文章

发布-订阅模式

发布-订阅模式 学习知识要善于思考&#xff0c;思考&#xff0c;再思考。 —— 爱因斯在众多设计模式中&#xff0c;可能最常见、最有名的就是发布 - 订阅模式了&#xff0c;本篇我们一起来学习这个模式。 发布 - 订阅模式 &#xff08;Publish-Subscribe Pattern, pub-sub&a…

什么是发布订阅模式?

发布-订阅模式&#xff08;Publish-Subscribe pattern&#xff09;是一种软件架构模式&#xff0c;用于实现组件之间的解耦和消息传递。在这种模式中&#xff0c;组件&#xff08;发布者&#xff09;将消息发送到一个中心&#xff08;消息代理或主题&#xff09;&#xff0c;然…

发布订阅模式

零、目录 应用场景实现原理代码实现全局模式下的订阅发布模式&#xff08;泛化的订阅发布模式&#xff09;总结 一、应用场景 ​ 发布订阅模式&#xff0c;广泛的存在于在我们的生活之中。 ​ 举个一个简单的例子来说&#xff0c;当我们在浏览视频或者博客论坛之类的网…

.NET(C#、VB)APP开发——Smobiler平台控件介绍:VLCPlayer

本文简述如何在Smobiler中使用VLCPlayer插件&#xff0c;该插件支持播放rtsp流。 Step 1. 新建一个SmobilerForm窗体&#xff0c;再拖入VLCPlay&#xff0c;布局如下 在设计器中给VLCPlayer.Url赋值或者在窗体的Load事件中赋值 演示使用的rtsp流地址 rtsp://wowzaec2demo.strea…

.NET(C#、VB)APP开发——Smobiler平台控件介绍:TTS

本文简述如何在Smobiler中使用TTS文字转语音。 Step 1. 新建一个SmobilerForm窗体&#xff0c;并在窗体中加入TTS和Button&#xff0c;布局如下 Button的点击事件代码&#xff1a; private void button1_Press(object sender, EventArgs e){ //第一个参数为文本&#xff1b;第…

Smobiler 仿得到APP个人主页

原型如下&#xff1a; 完整代码参考 https://github.com/comsmobiler/BlogsCode/blob/master/Source/BlogsCode_SmobilerForm/MyForm/dedao.cs 思路 可以将原型按照上图分成2个部分&#xff0c;部分A可以使用label、image、button、imagebutton、fontIcon控件来实现&#xff…

.NET(C#、VB)APP开发——Smobiler平台控件介绍:PDFView

本文简述如何在Smobiler中使用PDFView。 Step 1. 新建一个SmobilerForm窗体&#xff0c;再拖入PDfView&#xff0c;布局如下 PDFView.ResourcrPath默认Document&#xff0c;指项目下\Resources\Document&#xff0c;若是pdf文件放在该文件夹下&#xff0c;则在设计器中直接赋值…

.NET(C#、VB)APP开发——Smobiler平台控件介绍:OCR组件

本文简述如何在Smobiler中使用OCR组件进行文字识别。 Step 1. 新建一个SmobilerForm窗体&#xff0c;并在窗体中加入OCR和Button&#xff0c;布局如下 Button的点击事件代码&#xff1a; private void button1_Press(object sender, EventArgs e){ocr1.Recognize((obj,args)>…

.NET(C#、VB)APP开发——Smobiler平台控件介绍:ArcFace人脸识别

本文简述如何在Smobiler中使用ArcFace&#xff08;虹软人脸识别&#xff09;。 Step 1. 新建一个SmobilerForm窗体&#xff0c;再拖入Button,Label,TextBox和AcrFace,布局如下 在设计器中给MediaView.Url赋值或者在窗体的Load事件中赋值 Button的事件代码如下 string message …

移动OA办公——Smobiler第一个开源应用解决方案,快来get吧

产品简介 SmoONE是一款移动OA类的开源解决方案&#xff0c;通过Smobiler平台开发&#xff0c;包含了注册、登陆、用户信息等基本功能。集成了OA中使用场景较多的报销、请假、部门管理、成本中心等核心功能。 免费获取方案 开源代码&#xff1a;https://github.com/comsmobile…

.NET(C#、VB)APP开发——Smobiler平台控件介绍:UsbSerial串口通讯组件

本文简述如何在Smobiler中使用UsbSerial。 Step 1. 新建一个SmobilerForm窗体&#xff0c;再拖入UsbSerial和Button&#xff0c;布局如下 按钮事件代码&#xff1a; //连接private void button1_Press_2(object sender, EventArgs e){usbSerial1.Connect(Smobiler.Plugins.USBS…

Smobiler实现手机弹窗

前言 在实际项目中有很多场景需要用到弹窗&#xff0c;如图1 那么这些弹窗在Smobiler中如何实现呢&#xff1f; 正文 Smobiler实现弹窗有两种方式&#xff1a;1.MessageBox.Show 2.ShowDialog和ShowContextDialog。前者适合简易弹窗&#xff0c;后者适合自定义弹窗。 Messa…

Smobiler实现美观登录界面——C# 或.NET Smobiler实例开发手机app(二)

目录 一、 本文目标 二、 准备工作 1、 数据库 2、 材料 三、 界面布局 1、设置控件的属性值 &#xff08;1&#xff09; 输入框 &#xff08;2&#xff09; 图片属性 &#xff08;3&#xff09; HandElectricity的标题的label属性 &#xff08;4&#xff09;登录按钮…

.NET(C#、VB)APP开发——Smobiler平台控件介绍:MediaView

本文简述如何在Smobiler中使用MediaView。 Step 1. 新建一个SmobilerForm窗体&#xff0c;再拖入MediaView&#xff0c;MediaView.Size设置&#xff08;300,225&#xff09;,布局如下 在设计器中给MediaView.Url赋值或者在窗体的Load事件中赋值 播放本地视频可以通过GetResourc…

.NET(C#、VB)APP开发——Smobiler平台控件介绍:AliPay组件

本文简述如何在Smobiler中调用支付宝支付。 Step 1. 界面 新建一个窗体&#xff0c;并在窗体中拖入Button&#xff0c;Label&#xff0c;AliPay等控件&#xff0c;布局如下&#xff1a; Step 2. 代码 在窗体中声明变量 //订单编号private string tradeNo;//支付宝应用编号&am…

.NET(C#、VB)APP开发——Smobiler平台控件介绍:BarcodeReader组件

本文简述如何在Smobiler中使用BarcodeReader组件进行条码识别。Barcodereader通过机器学习能识别不规则条码&#xff0c;效率更好。 Step 1. 新建一个SmobilerForm窗体&#xff0c;并在窗体中加入Barcodereader和Button&#xff0c;布局如下 Button的点击事件代码&#xff1a; …

.NET(C#、VB)APP开发——Smobiler平台控件介绍:LiveStream和LiveStreamPlayer

本文简述如何在Smobiler中使用LiveStream和LiveStreamPlayer。 LiveStream 直播推送插件 Step 1. 新建一个SmobilerForm窗体&#xff0c;并在窗体中加入LiveStream和Button&#xff0c;布局如下 选中LisvStream&#xff0c;在设计器中设置Url&#xff08;需要事先准备一个视频…

【转载】smobiler说明

类似开发WinForm的方式&#xff0c;使用C#开发Android和IOS的移动应用&#xff1f;听起来感觉不可思议&#xff0c;那么Smobiler平台到底是如何实现的呢&#xff0c;这里给大家介绍一下。 客户端 Smobiler分为两种客户端&#xff0c;一种是开发版&#xff0c;一种是打包版 开发…

.NET(C#)能开发出什么样的APP?盘点那些通过Smobiler开发的移动应用

.NET程序员一定最熟悉所见即所得式开发,熟悉的Visual Studio开发界面,熟悉的C#代码。 Smobiler也是因为具备这样的特性,使开发人员,可以在VisualStudio上,像开发WinForm一样拖拉控件,让许多人在开发APP时,再次回到所见即所得的开发方式中去。 Smobiler的快速开发,让Ama…

.NET(C#、VB)APP开发——Smobiler平台控件介绍:MapView MaptrimView

本文简述如何在Smobiler中使用MapView和MaptrimView。 Mapview MapView 地图插件&#xff0c;可用于显示指定地点地图&#xff0c;显示轨迹等。 Step 1. 新建一个SmobilerForm窗体&#xff0c;再拖入MapView和Button&#xff0c;MapView.Size设置&#xff08;300,300&#xf…