观察者模式实战:解密最热门的设计模式之一

文章目录

  • 前言
  • 一、什么是观察者模式
  • 二、Java实现观察者模式
    • 2.1 观察者接口
    • 2.2 具体观察者
    • 2.3 基础发布者
    • 2.4 具体发布者
    • 2.5 消息发送
  • 三、Spring实现观察者模式
    • 3.1 定义事件类
    • 3.2 具体观察者
    • 3.3 具体发布者
    • 3.4 消息发送
  • 总结

前言

随着系统的复杂度变高,我们就会采取各种各样的优化手段来进行解耦,降低系统的复杂度,其中设计模式是古人经验的一种设计总结,场景一:发送消息的时候,需要采取不同的消息发送渠道,一次发送一个或者多个渠道,这种不确定的变化,我们就可以采用观察者模式来进行解耦,当一个对象状态发生改变时,其他依赖对象的状态也随之变更,这是观察者模式的核心。

注:本篇文章纯干货,采用Java的设计模式以及Spring设计模式实现,另外设计编码了交互页面,能够更直观体验观察者模式之美

一、什么是观察者模式

观察者模式是一种行为设计模式,类似于【发布订阅】,定义对象间的一种【一对多】的依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。

二、Java实现观察者模式

2.1 观察者接口

/*** 监听(观察者)接口* @author: DT辰白 Created by 2024/5/3 8:09*/
public interface EventListener {void update(String message);}

2.2 具体观察者

/*** 具体观察者* @author: DT辰白 Created by 2024/4/28 20:12*/
@Slf4j
@Service
public class EmailListener implements EventListener {@Overridepublic void update(String message) {log.info("邮箱:QQ邮箱发送消息,消息内容【{}】",message);}
}
/*** 具体观察者* @author: DT辰白 Created by 2024/4/28 20:14*/
@Slf4j
@Service
public class SmsListener implements EventListener {@Overridepublic void update(String message) {log.info("短信:短信发送消息,消息内容【{}】", message);}
}

2.3 基础发布者

这里我们使用了@Autowired注入,其实默认的实现类【EmailListener 、SmsListener】已经注入了,你也可以将List 做成一个普通的List集合,然后在使用的时候,将订阅对象添加到该List集合。

/*** @author: DT辰白 Created by 2024/4/28 20:17*/
@Component
public class EventManager {@Autowiredprivate List<EventListener> listeners;/*** 订阅* @param eventListeners*/public void subscribe(EventListener... eventListeners) {for (EventListener eventListener : eventListeners) {// 防止重复注入if (!listeners.contains(eventListener)) {this.listeners.add(eventListener);}}}/*** 取消订阅* @param eventListeners*/public void unsubscribe(EventListener... eventListeners) {for (EventListener eventListener : eventListeners) {listeners.remove(eventListener);}}/*** 通知* @param message*/public void notify(String message) {for (EventListener eventListener : listeners) {eventListener.update(message);}}
}

2.4 具体发布者

这里我们直接继承父类,可以通过子类调用父类的方法,我们也可以将此处做成一个抽象接口对外提供,具体方法有很多,根据自己的业务需求即可。

/*** 具体发布者* @author: DT辰白 Created by 2024/4/28 20:25*/
@Service
public class MessagePublisher extends EventManager {public void publishMessage(String message) {notify(message);}}

2.5 消息发送

@PostMapping(value = "/publishMessage")
@ApiOperation(value = "观察者模式【java】->发送消息")
public ResultUtil publishMessage(String message) {// 订阅(默认订阅全部)// messagePublisher.subscribe(emailListener,smsListener);// 取消订阅// messagePublisher.unsubscribe(smsListener);// 发布messagePublisher.publishMessage(message);return ResultUtil.success();
}
2024-05-03 08:25:17.049  INFO 12896 --- [nio-9091-exec-4] c.d.m.d.pattern.observer.EmailListener   : 邮箱:QQ邮箱发送消息,消息内容【我是一条鱼】
2024-05-03 08:25:17.049  INFO 12896 --- [nio-9091-exec-4] c.d.m.d.pattern.observer.SmsListener     : 短信:短信发送消息,消息内容【我是一条鱼】

三、Spring实现观察者模式

3.1 定义事件类

/*** 定义事件类* @author: DT辰白 Created by 2024/4/28 21:33*/
public class NotificationEvent extends ApplicationEvent {private String message;public NotificationEvent(Object source, String message) {super(source);this.message = message;}public String getMessage() {return message;}
}

3.2 具体观察者

/*** @author: DT辰白 Created by 2024/4/28 21:34*/
@Slf4j
@Component
public class EmailNotificationListener {@EventListenerpublic void onApplicationEvent(NotificationEvent event) {// 发送邮件通知log.info("邮箱:QQ邮箱发送消息,消息内容【{}】",event.getMessage());}
}
/*** @author: DT辰白 Created by 2024/4/28 21:34*/
@Slf4j
@Component
public class SMSNotificationListener {@EventListenerpublic void onApplicationEvent(NotificationEvent event) {// 发送短信通知log.info("短信:短信发送消息,消息内容【{}】", event.getMessage());}
}

3.3 具体发布者

/*** 发布者接口* @author: DT辰白 Created by 2024/4/28 21:35*/
public interface NotificationService {void notifyUsers(String message);
}
/*** 事件发布者* @author: DT辰白 Created by 2024/4/28 21:35*/
@Service
public class NotificationPublisher implements NotificationService {@Autowiredprivate ApplicationEventPublisher publisher;@Overridepublic void notifyUsers(String message) {publisher.publishEvent(new NotificationEvent(this, message));}
}

3.4 消息发送

@PostMapping(value = "/publishMsg")
@ApiOperation(value = "观察者模式【spring】->发送消息")
public ResultUtil publishMsg(String message) {notificationService.notifyUsers(message);return ResultUtil.success();
}
2024-05-03 10:39:14.302  INFO 12680 --- [nio-9091-exec-3] c.d.m.d.p.o.s.EmailNotificationListener  : 邮箱:QQ邮箱发送消息,消息内容【我是一条鱼】
2024-05-03 10:39:14.302  INFO 12680 --- [nio-9091-exec-3] c.d.m.d.p.o.s.SMSNotificationListener    : 短信:短信发送消息,消息内容【我是一条鱼】

以上方式为同步发送,如果不需要保证数据一致性,只要其中一个渠道消息发送成功即可,我们可以采用异步的方式发送,这样就不会影响其它正常的渠道发送,当然也是我们项目中常用的方式,发送失败的渠道,采用补偿机制或者人工介入重新发送即可。
在这里插入图片描述
最后,为了更直观的体验观察者模式,我们设计了一个交互页面:

在这里插入图片描述

总结

观察者模式是一种行为设计模式,定义了一种一对多的依赖关系,当一个对象状态发生变化时,所有依赖它的对象都会得到通知并自动更新。Spring中的事件驱动模型就是观察者模式的典型应用。

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

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

相关文章

ArmSoM-Sige5 RK3576开发板 正式发布!

简介​ ArmSoM-Sige5 采用Rockchip RK3576第二代8nm高性能AIOT平台&#xff0c;6 TOPS算力NPU&#xff0c;最大可配16GB大内存。支持8K视频编解码&#xff0c;拥有丰富的接口&#xff0c;支持双千兆网口&#xff0c;WiFi6 & BT5和多种视频输出。支持多种操作系统&#xff…

c#数据库:1.c#创建并连接数据库

安装软件:SQL Server Management Studio Management Studio Visual Studio 2022 启动服务: 打开SQL Server Management Studio Management Studio ,连接到服务器(GUANZU是我的计算机名) 新建数据库,随便起个名字叫aq: c#代码: using System; using System.Collections.Gener…

vue3 ——笔记 (表单输入,监听器)

表单输入 在Vue 3中&#xff0c;v-model指令的用法稍有不同于Vue 2。在Vue 3中&#xff0c;v-model指令实际上是一个语法糖&#xff0c;它会自动将value属性和input事件绑定到组件或元素上&#xff0c;以实现双向数据绑定。 在自定义组件中使用v-model时&#xff0c;需要在组…

STM32学习和实践笔记(24):PWM输出实验:呼吸灯

本实验所要实现的功能是&#xff1a;通过TIM3的CH1输出一个PWM信号&#xff0c;控制D7指示 灯由暗变亮&#xff0c;再由亮变暗&#xff0c;类似于人的呼吸。程序框架如下&#xff1a; &#xff08;1&#xff09;初始化PC6管脚为PWM输出功能 &#xff08;2&#xff09;PWM输出…

数组不为人知的一面,sizeof与strlen的区分

数组有另外一种表达方式&#xff0c;接下来我用代码的形式展现出来&#xff1a; sizeof 是一个操作符。 是用来计算变量&#xff08;类型&#xff09;所占内存空间大小&#xff0c;不关注内存中存放的具体内容。 单位是字节。 strlen 是一个库函数&#xff0c;是专门求字符…

Akamai 分布式“云+边缘”,打造下一代数字化基座

当下&#xff0c;数字化基础设施正逐步向分布式部署演化&#xff0c;云计算与边缘计算正在成为两大技术支柱。Gartner 数据显示&#xff0c;云服务占 IT 整体支出比例连年上涨&#xff0c;在过去一年已增长至12.1%&#xff1b;IDC 报告显示&#xff0c;截至2021年已有超过500亿…

【iOS】pthread、NSThread

文章目录 前言一、pthread 使用方法pthread 其他相关方法 二、 NSThread创建、启动线程线程相关用法线程状态控制方法NSThread 线程安全和线程同步场景 线程的状态转换 前言 五一这两天准备将GCD相关的知识完&#xff0c;同时NSOperation与NSThread、pthread也是相关知识&…

ffmpeg中stream_loop参数不生效原因分析

问题 使用ffmpeg把一个视频文件发布成一个rtmp流&#xff0c;并设置成循环推流&#xff0c;此时需要使用参数stream_loop&#xff0c;命令如下: ffmpeg.exe -stream_loop -1 -re -i D:\tools\ffmpeg-5.1.2\bin\sei.h264 -c copy -f flv -safe 0 rtmp://localhost:1935/live/te…

【Redis】Redis安装、配置、卸载使用可视化工具连接Redis

文章目录 1.前置条件2.安装Redis2.1下载Redis安装包并解压2.2在redis目录下执行make命令2.3修改Redis配置文件2.4启动Redis服务2.5连接redis服务 3.Redis卸载4.使用可视化工具连接Redis 1.前置条件 Linux操作系统需要要是64位.如果不清楚自己Linux上是多少位的,可以使用以下命…

Qt之信号与槽

槽的本质&#xff1a;对信号响应的函数。 信号函数和槽函数通常位于某个类中&#xff0c;和普通的成员函数相⽐&#xff0c;它们的特别之处在于&#xff1a; 信号函数⽤ signals 关键字修饰&#xff0c;槽函数⽤ public slots、protected slots 或者 private slots 修饰。sign…

数据结构:时间复杂度/空间复杂度

目录 一、时间复杂度 定义 常见的时间复杂度 如何计算时间复杂度 计算方法 三、实例分析 二、空间复杂度 定义 重要性 常见的空间复杂度 二、空间复杂度 定义 重要性 常见的空间复杂度 计算方法 三、实例分析 大O的渐进表示法 最好情况&#xff08;Best Case…

Java进阶-JINQ详解与使用

本文详细介绍了JINQ&#xff08;Java Integrated Query&#xff09;&#xff0c;一种强化Java中数据查询能力的库&#xff0c;提供类SQL的查询语法和类型安全的操作。文章首先解释了JINQ的基本功能和应用&#xff0c;随后通过具体示例展示了如何使用JINQ进行数据过滤、投影、连…

【竞技宝】意甲:退出齐尔克泽争夺战!国米免签伊朗神锋!

博洛尼亚中锋齐尔克泽成为了意甲当红炸子鸡,不少豪门球队都希望可以签下他,目前对球员有意向的俱乐部包括AC米兰、尤文图斯、阿森纳、国际米兰和曼联,看到自家球员如此有市场,博洛尼亚方面咬死5000万欧元的价格不松口,想要得到他必须要拿出真金白银。不过意甲霸主国际米兰率先退…

408数据结构-二叉树的概念、性质与存储结构 自学知识点整理

前置知识&#xff1a;树的基本概念与性质 二叉树的定义 二叉树是一种特殊的树形结构&#xff0c;其特点是每个结点至多只有两棵子树&#xff08;即二叉树中不存在度大于 2 2 2的结点&#xff09;&#xff0c;并且二叉树是有序树&#xff0c;左右子树不能互换。 与树类似&#…

笔试强训week3

day1 Q1 难度⭐ 牛牛冲钻五_牛客小白月赛38 (nowcoder.com) 题目&#xff1a; 牛牛最近在玩炉石传说&#xff0c;这是一款一对一对战的卡牌游戏&#xff0c;牛牛打算努力冲上钻五分段&#xff0c;获得丰厚的天梯奖励。 炉石传说的段位可以用星数来表示&#xff0c;具体规则…

【linuxC语言】空洞文件

文章目录 前言一、空洞文件1.1 空洞文件的介绍1.2 用途 二、示例代码总结 前言 在 Linux 系统编程中&#xff0c;空洞文件是一种特殊类型的文件&#xff0c;它包含了逻辑上的空洞&#xff0c;也就是说文件中的某些部分并没有实际写入数据。尽管文件在逻辑上可能非常大&#xf…

webpack 常用插件

clean-webpack-plugin 这个插件的主要作用是清除构建目录中的旧文件&#xff0c;以确保每次构建时都能得到一个干净的环境。 var { CleanWebpackPlugin } require("clean-webpack-plugin") const path require("path");module.exports {mode: "de…

Springboot+mybatis升级版(Postman测试)

一、项目结构 1.导入依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apach…

12_Scala_package

文章目录 Scaal面向对象编程1.回顾Java2.package可以多次声明3.设置作用域&#xff0c;设置上下级4.包可以当作对象使用5.import6.Scala用_取代Java *7.导入多个包8.屏蔽类9.类起别名10.import的规则11.有些包无需导入 Scaal面向对象编程 Scala是一门完全面向对象语言&#xf…

Linux的权限管理

文章目录 文件权限文件类型文件访问者的分类文件权限的类型 文件访问权限的设置目录的权限 文件权限 对于每个LInux文件&#xff0c;如果用ll指令查看的话&#xff0c;可以发现每个文件前面都有一串类似的字符&#xff1a; 这里总共有十个字符&#xff0c;其中第一个字符表示…