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

news2024/10/5 21:25:24

文章目录

  • 前言
  • 一、什么是观察者模式
  • 二、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 {

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

    @Override
    public 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 {

    @Autowired
    private 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 {
    @EventListener
    public void onApplicationEvent(NotificationEvent event) {
        // 发送邮件通知
        log.info("邮箱:QQ邮箱发送消息,消息内容【{}】",event.getMessage());
    }
}
/**
 * @author: DT辰白 Created by 2024/4/28 21:34
 */
@Slf4j
@Component
public class SMSNotificationListener {
    @EventListener
    public 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 {

    @Autowired
    private ApplicationEventPublisher publisher;

    @Override
    public 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.coloradmin.cn/o/1640468.html

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

相关文章

Google 发布 CodeGemma 7B,8K上下文,性能超CodeLlama 13B

CodeGemma简介 CodeGemma模型是谷歌的社区开放编程模型&#xff0c;专门针对代码领域进行优化。一系列功能强大的轻量级模型&#xff0c;能够执行多种编程任务&#xff0c;如中间代码填充、代码生成、自然语言理解、数学推理和指令遵循。CodeGemma模型是在大约500B个主要为英语…

【算法入门教育赛1D】环形密码 - 字符串 | C++题解与代码

题目链接&#xff1a;https://www.starrycoding.com/problem/161 题目描述 小 e e e有一个宝箱&#xff0c;这个宝箱有一个长度为 n n n的密码&#xff0c;但是这个密码校验器是一个环形&#xff0c;意思是只要密码从任意一位开始读&#xff08;读到最后一位回到第一位继续&a…

每日OJ题_贪心算法二⑤_力扣870. 优势洗牌(田忌赛马)

目录 力扣870. 优势洗牌&#xff08;田忌赛马&#xff09; 解析代码 力扣870. 优势洗牌&#xff08;田忌赛马&#xff09; 870. 优势洗牌 难度 中等 给定两个长度相等的数组 nums1 和 nums2&#xff0c;nums1 相对于 nums2 的优势可以用满足 nums1[i] > nums2[i] 的索引…

Redis - Zset 有序集合

前言 它保留了集合不能有重复成员的特点&#xff0c;但与集合不同的是&#xff0c;有序集合中的每个元素都有⼀个唯⼀的浮点类型的分数&#xff08;score&#xff09;与之关联&#xff0c;有序集合中的元素是可以维护有序性的&#xff0c;但这个有序不是⽤下标作为排序依据⽽是…

笔记13-OSError: [Errno 24] Too many open files

文章目录 参考文献失败尝试系列查看发现&#xff0c;似乎是因为线程数有限制 修改配置先查查看 增加文件数限制&#xff0c;然后使用命令运行&#xff08;成功&#xff09; 参考文献 Linux 最大可以打开多少文件描述符&#xff1f; OSError: [Errno 24] Too many open files错…

Redis-单机安装

试图从官网注册不了我也不知道什么情况。 网盘自取吧&#xff0c;链接&#xff1a;https://pan.baidu.com/s/1KERBQaH9gCT10AGt9z0_jg?pwdyjen 安装比较简单&#xff0c;照着敲就完了每一步都试过了&#xff0c;先单机安装&#xff0c;后面搭建集群。 1.将安装包放到/usr/…

一文带你了解MySQL的索引分类

文章目录 ☃️分类☃️演示图☃️思考☃️总结 欢迎来到 请回答1024 的博客 &#x1f353;&#x1f353;&#x1f353;欢迎来到 请回答1024的博客 关于博主&#xff1a; 我是 请回答1024&#xff0c;一个追求数学与计算的边界、时间与空间的平衡&#xff0c;0与1的延伸的后端开…

C++之set/map相关实现

看着上面的图片&#xff0c;你可能对set和map的多样变化产生疑惑&#xff0c;下面我们就来详细讲解他们的区别以及实现 一.set/map 首先&#xff0c;在这里我们要声明&#xff0c;如果你对二叉搜索树一点都不了解的话&#xff0c;建议你先去将搜索二叉树学会再来学习这里的内…

MFC 列表控件删除实例(源码下载)

1、本程序基于前期我的博客文章《MFC下拉菜单打钩图标存取实例&#xff08;源码下载) 》 2、程序功能选中列表控件某一项&#xff0c;删除按钮由禁止变为可用&#xff0c;点击删除按钮&#xff0c;选中的项将删除。 3、首先在主界面添加一个删除参数按钮。 4、在myDlg.cpp 文件…

Python语言零基础入门——文件

目录 一、文件的基本概念 1.文件 2.绝对路径与相对路径 3.打开文件的模式 二、文件的读取 三、文件的追加 四、文件的写入 五、with语句 六、csv文件 1.csv文件的读取 2.csv文件的写入 七、练习题&#xff1a;实现日记本 一、文件的基本概念 1.文件 文件是以计算…

win10禁止自动更新的终极方法

添加注册表值 1.运行&#xff0c;输入regedit 2.打开注册表编辑器依次进入以下路径“计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings”。 3.在Settings项中&#xff0c;新建DWORD&#xff08;32位&#xff09;值(D)&#xff0c;重命名为以下命名“Fl…

python判断大图中包含小图并输出位置总结

python判断大图中包含小图并输出位置总结 没啥可说的&#xff0c;项目遇到了就直接上代码&#xff0c;可以减轻劳动力&#xff0c;花最少得时间实现应用功能。 import cv2 # 读取大图片和小图片的路径 img_big cv2.imread(big_image.png) img_small cv2.imread(small_image…

使用protoc-jar-maven-plugin生成grpc项目

在《使用protobuf-maven-plugin生成grpc项目》中我们使用protobuf-maven-plugin完成了grpc代码的翻译。本文我们将只是替换pom.xml中的部分内容&#xff0c;使用protoc-jar-maven-plugin来完成相同的功能。总体来说protoc-jar-maven-plugin方案更加简便。 环境 见《使用proto…

数据结构--顺序表经典OJ题

例1&#xff1a;合并有序顺序表 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2&#xff0c;另有两个整数 m 和 n &#xff0c;分别表示 nums1 和 nums2 中的元素数目。请你 合并 nums2 到 nums1 中&#xff0c;使合并后的数组同样按 非递减顺序 排列。 注意&#xff…

R可视化:分组频率分布直方图和密度图

介绍 ggplot2绘制分组频率分布直方图和密度图 加载R包 knitr::opts_chunk$set(message FALSE, warning FALSE) library(tidyverse) library(patchwork) library(ggpubr) library(rstatix)# rm(list ls()) options(stringsAsFactors F) options(future.globals.maxSize …

数据结构与算法---树

数据结构可视化网址 Structure Visualization: https://www.cs.usfca.edu/~galles/visualization/Totuma: https://www.totuma.cn/Algorithm Visualizer: https://algorithm-visualizer.org/ 构建二叉树 // C#include<stdio.h> #include<stdlib.h>typedef char T…

电脑找不到msvcp140.dll如何修复?msvcp140.dll丢失的多种解决方法分享

在日常电脑操作过程中&#xff0c;用户可能会遇到一个令人困扰的问题&#xff0c;即屏幕上突然弹出一条错误提示&#xff1a;“由于找不到msvcp140.dll&#xff0c;无法继续执行代码”。这一情况往往导致应用程序无法正常启动或运行&#xff0c;给工作和娱乐带来不便。不过&…

freertos入门---创建FreeRTOS工程

freertos入门—创建FreeRTOS工程 1 STM32CubeMx配置 双击运行STM32CubeMX,在首页选择“ACCESS TO MCU SELECTOR”,如下图所示&#xff1a;   在MCU选型界面&#xff0c;输入自己想要开发的芯片型号&#xff0c;如&#xff1a;STM32F103C8T6: 2 配置时钟 在“System Core”…

【MATLAB】解决不同版本MATLAB出现中文乱码的问题

解决不同版本MATLAB出现中文乱码的问题 方法1&#xff1a;更改保存类型为GBK方法2&#xff1a;记事本打开方法3&#xff1a;Notepad参考 低版本matlab打开高版本Matlab的.m文件时&#xff0c;出现中文乱码问题。比如下图&#xff1a; 出现原因为&#xff1a; 编码格式不统一问…

【深度学习】第二门课 改善深层神经网络 Week 1 深度学习的实践层面

&#x1f680;Write In Front&#x1f680; &#x1f4dd;个人主页&#xff1a;令夏二十三 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd; &#x1f4e3;系列专栏&#xff1a;深度学习 &#x1f4ac;总结&#xff1a;希望你看完之后&#xff0c;能对…