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

文章目录

  • 前言
  • 一、什么是观察者模式
  • 二、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.mzph.cn/web/6256.shtml

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

相关文章

vivado Aurora 8B/10B IP核(9)- CRC、 Aurora 8B/10B内核的时钟接口端口

CRC 模块提供 16 位或 32 位 CRC&#xff0c;用于用户数据。 Aurora 8B/10B 内核的时钟接口端口 从相邻收发器四边形的时钟Xilinx 实现工具可以根据需要对南北路由和引脚交换到收发器时钟输入进行必要的调整&#xff0c;以将时钟从一个四线到另一个。 重要信息&#xff1a;共…

踏上R语言之旅:解锁数据世界的神秘密码(五)

线性与非线性模型及R使用 文章目录 线性与非线性模型及R使用一、数据的分类与模型选择1.变量的取值类型 二、广义线性模型广义线性模型概述Logistic模型 总结 一、数据的分类与模型选择 1.变量的取值类型 因变量记为y&#xff0c;解释变量记为x1&#xff0c;x2,… 因变量y一般…

第三节课,功能2:开发后端用户的管理接口-- postman--debug测试

一、如何使用postman 网址&#xff1a; https://www.postman.com/downloads/ 【Postman小白教程】五分钟学会如何使用Postman~_哔哩哔哩_bilibili postman安装使用_bowser agent在postman哪里-CSDN博客 二、下载后 登录&#xff0c;开始测试 2.1 关于postman 报错&#…

MTEB - Embedding 模型排行榜

文章目录 关于 MTEBMTEB 任务和数据集概览使用 MTEB Pythont 库Installation使用 关于 MTEB MTEB : Massive Text Embedding Benchmark github : https://github.com/embeddings-benchmark/mtebhuggingface : https://huggingface.co/spaces/mteb/leaderboardpaper : https:/…

【Java EE】CAS原理和实现以及JUC中常见的类的使用

˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解&#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如…

asyncionetworkxFuncAnimation学习--动态显示计算图的运行情况

asyncio&networkx&FuncAnimation学习--动态显示计算图的运行情况 一.效果二.代码 一.目的 1.动态显示计算图的运行状态(点或边是否已完成) 二.步骤: 1.定义计算图 2.asyncio 并行计算 3.networkx 显示计算图 4.FuncAnimation 动态更新 三.依赖: conda install pygraphv…

数据结构--栈与队列【您的关注是我创作的动力!】

文章目录 栈什么是栈&#xff1f;栈的具体实现 队列什么是队列&#xff1f;队列的实现 栈 什么是栈&#xff1f; 栈也是顺序表的一种&#xff0c;栈的逻辑实现是先进后出&#xff08;后进先出&#xff09;就跟子弹夹一样。 具体逻辑就是它只允许在固定的一端进行数据的插入与…

PHP源码_最新Ai对话系统网站源码 ChatGPT+搭建教程+前后端

基于ChatGPT开发的一个人工智能技术驱动的自然语言处理工具&#xff0c;它能够通过学习和理解人类的语言来进行对话&#xff0c;还能根据聊天的上下文进行互动&#xff0c;真正像人类一样来聊天交流&#xff0c;甚至能完成撰写邮件、视频脚本、文案、翻译、代码&#xff0c;写论…

C# Web控件与数据感应之 CheckBoxList 类

目录 关于数据感应 CheckBoxList 类 范例运行环境 数据源表设计 角色字典表 用户角色表 AutoValueDBList 方法 原理 设计 实现 调用示例 初始化数据 启动查询模式 使用保存模式 小结 关于数据感应 数据感应也即数据捆绑&#xff0c;是一种动态的&#xff0c;We…

【Docker学习】docker version查看版本信息

就像很多应用一样&#xff0c;docker也使用version来查看版本信息。但因为docker包含有不少独立组件&#xff0c;version的作用范围会更广一些。 用法1&#xff1a; docker --version 描述&#xff1a; 输出安装的Docker CLI 的版本号。关于Docker CLI&#xff0c;请访问。 实操…

项目管理-项目范围管理2/2

项目管理&#xff1a;每天进步一点点~ 活到老&#xff0c;学到老 ヾ(◍∇◍)&#xff89;&#xff9e; 何时学习都不晚&#xff0c;加油 项目范围管理&#xff0c;过程 6个&#xff0c;包括“规收定 创确控”&#xff1a; 规划范围管理收集需求定义范围创建WBS确认范围控制…

怎么证明E[E(X|Y,Z)Y]= E(X|Y)

性质8的证明 物理意义

webpack基础---常用loader

webpack 命令式和配置文件 html-webpack-plugin 配置项&#xff1a;{ templete: filename: inject: } 清除上次打包的文件&#xff0c;output: { clear: true } mode选项&#xff1a; none development prodution souce-map&#xff1a;可以精准定位代码行数 { devt…

【Android学习】简易计算器的实现

1.项目基础目录 新增dimens.xml 用于控制全部按钮的尺寸。图片资源放在drawable中。 另外 themes.xml中原来的 <style name"Theme.Learn" parent"Theme.MaterialComponents.DayNight.DarkActionBar">变为了&#xff0c;加上后可针对button中增加图片…

发卡授权盗u系统源码ZHU

2024最新UI发卡盗U/支持多语言/更新UI界面/支持多个主流钱包去除后门板&#xff0c; 搭建系统TGaqxm01&#xff0c;最好是部署智能合约后用合约地址来授权包含转账支付页面盗U授权源码。 完美提U&#xff0c;教程包含如何提u 。功能完美。 1.Php静态 2.目录puicta 3.扩sal 4.s…

Spring Boot中使用Redis和Lua脚本实现延时队列

码到三十五 &#xff1a; 个人主页 延时队列是一种常见的需求。延时队列允许我们延迟处理某些任务&#xff0c;这在处理需要等待一段时间后才能执行的操作时特别有用&#xff0c;如发送提醒、定时任务等。文中&#xff0c;将介绍如何在Spring Boot环境下使用Redis和Lua脚本来实…

吴恩达机器学习笔记 三十七 电影推荐系统 使用特征 成本函数 协同过滤算法

以电影评分系统为例&#xff0c;令 r(i, j) 来表示用户 j 已经对电影 i 评分&#xff0c; y&#xff08;i, j&#xff09;表示评分具体是多少。 假如每部电影有自己的特征&#xff0c;那么用户 j 对电影 i 的评分预测为 w(j) * x(i) b(j) r(i, j) &#xff1a;一个用户 j 是否…

global IoT SIM解决方案

有任何关于GSMA\IOT\eSIM\RSP\业务应用场景相关的问题&#xff0c;欢迎W: xiangcunge59 一起讨论, 共同进步 (加的时候请注明: 来自CSDN-iot). Onomondo提供的全球IoT SIM卡解决方案具有以下特点和优势&#xff1a; 1. **单一全球配置文件**&#xff1a;Onomondo的SIM卡拥…

Flink checkpoint 源码分析- Checkpoint barrier 传递源码分析

背景 在上一篇的博客里&#xff0c;大致介绍了flink checkpoint中的触发的大体流程&#xff0c;现在介绍一下触发之后下游的算子是如何做snapshot。 上一篇的文章: Flink checkpoint 源码分析- Flink Checkpoint 触发流程分析-CSDN博客 代码分析 1. 在SubtaskCheckpointCoo…

Vue3+ts(day05:ref、props、生命周期、hook)

学习源码可以看我的个人前端学习笔记 (github.com):qdxzw/frontlearningNotes 觉得有帮助的同学&#xff0c;可以点心心支持一下哈&#xff08;笔记是根据b站上学习的尚硅谷的前端视频【张天禹老师】&#xff0c;记录一下学习笔记&#xff0c;用于自己复盘&#xff0c;有需要学…