【设计模式-行为型】观察者模式
一、什么是观察者模式
说起观察者模式,不得不说一位观察者模式的高级应用者,朱元璋。不知道大家有没有看过胡军演的电视剧《朱元璋》。这部剧背景是元朝末年,天下大乱,朱元璋自幼父母双亡,沦为乞丐,后遁入空门,最终加入义军,南征北战,一步步登上历史舞台。剧中对朱元璋的刻画非常细腻,展现了他从底层一步步走向权力巅峰的过程。
在剧中,朱元璋为了巩固皇权,设立了锦衣卫。这一情节反映了朱元璋对权力的绝对掌控和对潜在威胁的高度警惕。其中有一个电影情结,让我记忆深刻:
监视闲赋在家的刘伯温 -------情节还原
-
刘伯温罢官回乡:朱元璋在经历了杨宪事件后变得更加多疑,开始怀疑刘伯温及其他官员。为了加强对官员的监控,朱元璋密令二虎组建了一支秘密队伍,命名为“锦衣卫”,专门监视所有皇孙臣子。刘伯温因与朱元璋政见不合,被朱元璋拒见并逐渐被孤立。刘伯温意识到朱元璋可能随时会治他的罪,于是提前写好了遗嘱。
-
归乡途中被监视:刘伯温在归乡途中被锦衣卫检校吴风半路拦截,奉命护送他回青田老家。刘伯温这才断定朱元璋可能要对他不利。在护送过程中,吴风等人虽然表面上照顾刘伯温父子的起居,但实际上一直在监视他们的行动和对话。刘伯温等待着吴风的诛杀,但直到抵达青田老家,吴风也没有动手,这让刘伯温感到非常诧异。
-
后续发展:朱元璋不断赏赐刘伯温,试图通过这种方式让刘伯温回京。刘伯温最终决定回京,但吴风再次出现,奉命护送他返回京城。
这一情节生动地体现了观察者模式的核心逻辑:通过“观察者”(锦衣卫)监视“被观察对象”(刘伯温),并将情报汇报给“主题”(朱元璋)。这种模式不仅巩固了朱元璋的皇权,还通过动态监控和及时反应,确保了明朝初年的政治稳定。基于上面的例子,我们来解释一下什么是观察者模式:观察者模式是一种行为型设计模式,它通过定义对象之间的依赖关系,使得当一个对象(主题)的状态发生变化时,所有依赖于它的对象(观察者)都会自动得到通知并更新。这种模式非常适合用于“一对多”的依赖关系,其中一个对象的状态变化需要通知多个其他对象。
二、为什么用观察者模式
通过这个例子来说明一下为什么要使用观察者模式呢(朱元璋为啥使用锦衣卫)
-
解耦合:观察者模式使得主题和被观察对象之间松耦合,主题不需要直接与被观察对象互动,而是通过观察者获取信息。朱元璋(主题)不需要直接与刘伯温(被观察对象)互动,而是通过锦衣卫(观察者)来获取信息。这种间接的监控方式使得朱元璋和刘伯温之间保持了松耦合关系。朱元璋不需要了解刘伯温的具体行动细节,只需要通过锦衣卫获取关键信息,从而减少了直接干预带来的风险。
-
动态监控:观察者模式支持动态监控,主题可以实时获取被观察对象的状态变化,并及时做出反应。朱元璋需要实时掌握刘伯温的动态,以便在必要时采取行动。通过锦衣卫的监视,朱元璋可以在刘伯温有任何异常行为时迅速做出反应,确保皇权的稳固。
-
集中管理:观察者模式通过统一的接口管理多个观察者,使得主题能够集中管理所有观察者的行为。这提高了系统的整体协调性和一致性。朱元璋通过锦衣卫统一管理对刘伯温的监视,确保所有信息都能集中汇报到他这里。这种集中管理的方式使得朱元璋能够全面掌握局势,避免信息碎片化,从而更好地做出决策。
-
扩展性:观察者模式允许动态地添加或删除观察者,而不需要修改主题的代码。这使得系统在运行时可以根据需要灵活调整监控范围和方式。朱元璋还可以添加监控对象胡惟庸,后续剧情。
-
广播通信:观察者模式支持一对多的广播通信机制,当主题的状态发生变化时,所有观察者都会收到通知。这使得系统能够高效地传递信息,减少重复劳动。指令统一由朱元璋下达,广播给锦衣卫。
三、观察者模式示例
3.1 锦衣卫Demo
下面让我们来用代码还原一下场景:
- 定义锦衣卫行为(接收任务,反馈监听信息)
public interface Observer {void receiveTask(String taskDescription); // 接收监听任务void reportBack(String report); // 向朱元璋反馈信息 } - 定义主题类朱元璋的行为
import java.util.List;public interface Subject {void assignTask(String taskDescription); // 下达监听任务void receiveReport(String report); // 接收反馈 } - 定义具体主题类朱元璋
import java.util.ArrayList; import java.util.List;public class ZhuYuanZhang implements Subject {private List<Observer> observers = new ArrayList<>();@Overridepublic void assignTask(String taskDescription) {System.out.println("朱元璋下达监听任务:" + taskDescription);for (Observer observer : observers) {observer.receiveTask(taskDescription);}}@Overridepublic void receiveReport(String report) {System.out.println("朱元璋收到反馈:" + report);}public void registerObserver(Observer observer) {observers.add(observer);}public void removeObserver(Observer observer) {observers.remove(observer);} } - 定义具体实行监听示例锦衣卫(二虎小弟):锦衣卫作为观察者,负责监视刘伯温的行动,并向朱元璋汇报。
public class JinyiWei implements Observer {private String name;private Subject zhuYuanZhang;public JinyiWei(String name, Subject zhuYuanZhang) {this.name = name;this.zhuYuanZhang = zhuYuanZhang;}@Overridepublic void receiveTask(String taskDescription) {System.out.println(name + " 接收到任务:" + taskDescription);// 模拟监听过程String report = performMonitoring(taskDescription);// 向朱元璋反馈信息reportBack(report);}@Overridepublic void reportBack(String report) {zhuYuanZhang.receiveReport(report);}private String performMonitoring(String taskDescription) {// 模拟监听过程return "监听结果:刘伯温 " + taskDescription;} } - 开始监听刘伯温
public class Main {public static void main(String[] args) {// 创建朱元璋(主题)Subject zhuYuanZhang = new ZhuYuanZhang();// 创建锦衣卫(观察者)Observer jinyiWei1 = new JinyiWei("锦衣卫 A", zhuYuanZhang);Observer jinyiWei2 = new JinyiWei("锦衣卫 B", zhuYuanZhang);// 注册锦衣卫zhuYuanZhang.registerObserver(jinyiWei1);zhuYuanZhang.registerObserver(jinyiWei2);// 朱元璋下达监听任务zhuYuanZhang.assignTask("监视刘伯温在青田老家的行动");zhuYuanZhang.assignTask("监视刘伯温准备回京的行动");// 移除一个锦衣卫zhuYuanZhang.removeObserver(jinyiWei1);// 再次下达监听任务zhuYuanZhang.assignTask("监视刘伯温抵达京城后的行动");} }// 朱元璋下达监听任务:监视刘伯温在青田老家的行动 锦衣卫 A 接收到任务:监视刘伯温在青田老家的行动 锦衣卫 B 接收到任务:监视刘伯温在青田老家的行动 朱元璋收到反馈:监听结果:刘伯温 在青田老家与旧部密谈 朱元璋收到反馈:监听结果:刘伯温 在青田老家与旧部密谈 朱元璋下达监听任务:监视刘伯温准备回京的行动 锦衣卫 A 接收到任务:监视刘伯温准备回京的行动 锦衣卫 B 接收到任务:监视刘伯温准备回京的行动 朱元璋收到反馈:监听结果:刘伯温 准备回京,行动异常 朱元璋收到反馈:监听结果:刘伯温 准备回京,行动异常 朱元璋下达监听任务:监视刘伯温抵达京城后的行动 锦衣卫 B 接收到任务:监视刘伯温抵达京城后的行动 朱元璋收到反馈:监听结果:刘伯温 抵达京城后与胡惟庸密会
3.2 Spring 事件机制与消息队列(MQ)的观察者模式
在实际应用中,我们一般不自己实现观察者模式,多数使用到的是Spring 事件机制和消息队列(MQ)。
3.2.1 Spring 中观察者模式的四个角色
-
事件(Event):
-
定义:
ApplicationEvent是所有事件对象的父类,继承自 JDK 的EventObject。 -
作用:所有自定义事件都需要继承
ApplicationEvent,并通过getSource()方法获取事件源。 -
内置事件:Spring 提供了多种内置事件,如
ContextRefreshedEvent、ContextStartedEvent、ContextStoppedEvent、ContextClosedEvent和RequestHandledEvent。
-
-
事件监听器(Listener):
-
定义:
ApplicationListener是事件监听器接口,继承自 JDK 的EventListener。 -
作用:监听器通过实现
onApplicationEvent(ApplicationEvent event)方法来处理事件。当事件发生时,Spring 会调用此方法。 -
实现方式:可以通过实现
ApplicationListener接口或使用@EventListener注解来定义监听器。
-
-
事件源(Event Source):
-
定义:
ApplicationContext是 Spring 的核心容器,也是事件的发布者。 -
作用:
ApplicationContext继承自ApplicationEventPublisher,通过publishEvent(Object event)方法发布事件。 -
发布方式:事件可以由任何组件通过调用
ApplicationContext的publishEvent方法发布。
-
-
事件管理器(Event Multicaster):
-
定义:
ApplicationEventMulticaster是事件管理器,负责事件监听器的注册和事件的广播。 -
作用:当
ApplicationContext发布事件时,ApplicationEventMulticaster负责将事件广播给所有注册的监听器。 -
注册方式:监听器可以通过注解(如
@EventListener)或通过实现ApplicationListener接口并注册到ApplicationContext中。
-
3.2.2 Spring事件与MQ的对比
| 场景 | Spring 事件机制 | 消息队列(MQ) |
|---|---|---|
| 单体应用内部事件传递 | ✅ 适合,低延迟 | ❌ 过于复杂,性能未必优于直接调用 |
| 分布式系统通信 | ❌ 需额外实现跨容器事件传递 | ✅ 天然支持分布式,适合跨系统通信 |
| 高可靠性场景 | ❌ 容器故障可能导致事件丢失 | ✅ 提供持久化和重试机制,确保消息不丢失 |
| 大规模并发消息处理 | ❌ 不支持高并发场景 | ✅ 专为高并发设计,支持海量消息传递 |
| 事务一致性要求高的场景 | ❌ 无原生事务支持,需手动处理 | ✅ 提供事务机制(如 Kafka 事务 API) |
| 消息顺序严格要求的场景 | ❌ 无顺序性保障 | ✅ 支持消息顺序(如 Kafka 分区内消息有序) |
相关文章:
【设计模式-行为型】观察者模式
一、什么是观察者模式 说起观察者模式,不得不说一位观察者模式的高级应用者,朱元璋。不知道大家有没有看过胡军演的电视剧《朱元璋》。这部剧背景是元朝末年,天下大乱,朱元璋自幼父母双亡,沦为乞丐,后遁入空…...
从理论到实践:Django 业务日志配置与优化指南
在现代 Web 开发中,日志记录是确保系统可维护性和可观测性的重要手段。通过合理的日志配置,我们可以快速定位问题、分析系统性能,并进行安全审计。本文将围绕 Django 框架,详细介绍如何配置和优化业务日志,确保开发环境和生产环境都能高效地记录和管理日志。 © ivwdc…...
Linux下php8安装phpredis扩展的方法
Linux下php8安装phpredis扩展的方法 下载redis扩展执行安装编辑php.ini文件重启php-fpmphpinfo 查看 下载redis扩展 前提是已经安装好redis服务了 php-redis下载地址 https://github.com/phpredis/phpredis 执行命令 git clone https://github.com/phpredis/phpredis.git执行…...
Flink运行时架构
一、系统架构 1)作业管理器(JobManager) JobManager是一个Flink集群中任务管理和调度的核心,是控制应用执行的主进程。也就是说,每个应用都应该被唯一的JobManager所控制执行。 JobManger又包含3个不同的组件。 &am…...
JupyterLab 安装以及部分相关配置
安装 JupyterLab pip install jupyter启动 JupyterLab jupyter lab [--port <指定的端口号>] [--no-browser] # --port 指定端口 # --no-browser 启动时不打开浏览器安装中文 首先安装中文包 pip install jupyterlab-language-pack-zh-CN安装完成后重启 JupyterLab 选…...
PC端实现PDF预览(支持后端返回文件流 || 返回文件URL)
一、使用插件 插件名称:vue-office/pdf 版本:2.0.2 安装插件:npm i vue-office/pdf^2.0.2 1、“vue-office/pdf”: “^2.0.2”, 2、 npm i vue-office/pdf^2.0.2 二、代码实现 // 引入组件 (在需要使用的页面中直接引入&#x…...
大模型 / 智能体在智能运维领域的应用总结与发展趋势概述
智能体 智能运维 ? 回顾大模型的发展 大模型的发展在过去两年间呈现出爆炸式的增长,成为推动人工智能领域快速进步的关键力量。 2023年3月:百度发布了其知识增强的大语言模型产品“文心一言”,这标志着国内AI大模型产业竞争的…...
uniapp 在线更新应用
在线更新应用及进度条显示 1.比较现安装手机中的apk 与线上apk的版本 getVersion(){var newVersionuni.getStorageSync("newVersion").split(".")var versionplus.runtime.version.split(".") // 获取手机安装的版本var versionNum""…...
AIGC视频生成模型:ByteDance的PixelDance模型
大家好,这里是好评笔记,公主号:Goodnote,专栏文章私信限时Free。本文详细介绍ByteDance的视频生成模型PixelDance,论文于2023年11月发布,模型上线于2024年9月,同时期上线的模型还有Seaweed&…...
python远程获取数据库中的相关数据并存储至json文件
1. conn中的5个变量的含义: ① Driver:数据库驱动程序,我使用的是SQL Server数据库。 ② Server:数据库所在的服务器地址。 ③ Database:要连接的数据库的名称。 ④ UID:登录 SQL Server 数据库的用户名…...
Kubernetes v1.28.0安装dashboard v2.6.1(k8s图形化操作界面)
准备工作 Kubernetes v1.28.0搭建教程请参考:Kubernetes v1.28.0集群快速搭建教程-CSDN博客 查看当前集群nodes都是ready状态 查看当前pods都是running状态 下载并修改配置文件 下载 recommended.yaml ,下载好之后,进入文件编辑 下载地址…...
详解三种常用标准化:Batch Norm、Layer Norm和RMSNorm
在深度学习中,标准化技术是提升模型训练速度、稳定性和性能的重要手段。本文将详细介绍三种常用的标准化方法:Batch Normalization(批量标准化)、Layer Normalization(层标准化)和 RMS Normalization&#…...
linux+docker+nacos+mysql部署
一、下载 docker pull mysql:5.7 docker pull nacos/nacos-server:v2.2.2 docker images 二、mysql部署 1、创建目录存储数据信息 mkdir ~/mysql cd ~/mysql 2、运行 MySQL 容器 docker run -id \ -p 3306:3306 \ --name mysql \ -v $PWD/conf:/etc/mysql/conf.d \ -v $PWD/…...
如何实现gitlab和jira连通
将 GitLab 和 Jira 集成起来可以实现开发任务与代码变更的联动,提高团队协作效率。以下是实现两者连通的详细步骤: 1. 确保必要条件 在进行集成之前,确保以下条件满足: 你有 GitLab 和 Jira 的管理员权限。Jira 是 Jira Cloud 或…...
利用ML.NET精准提取人名
在当今信息爆炸的时代,文本处理任务层出不穷,其中人名提取作为基础且重要的工作,广泛应用于信息检索、社交网络分析、客户关系管理等领域。随着人工智能不断进步,ML.NET作为微软推出的开源机器学习框架,为开发者提供了…...
Node.js的解释
1. Node.js 入门教程 1.1 什么是 Node.js? 1.1.1 Node.js 是什么? Node.js 是一个基于 JavaScript 的开源服务器端运行时环境,允许开发者用 JavaScript 编写服务器端代码。与传统的前端 JavaScript 主要运行在浏览器端不同,Nod…...
Macos下交叉编译安卓的paq8px压缩算法
官方没有android的编译方法,自己编写脚本在macos下交叉编译. 下载源码: git clone https://github.com/hxim/paq8px.git 稍旧的ndk并不能编译成功,需要下载最新的ndkr27c, 最后是使用clang来编译。 编译build.sh export ANDROID_NDK/Vol…...
如何在data.table中处理缺失值
📊💻【R语言进阶】轻松搞定缺失值,让数据清洗更高效! 👋 大家好呀!今天我要和大家分享一个超实用的R语言技巧——如何在data.table中处理缺失值,并且提供了一个自定义函数calculate_missing_va…...
从零安装 LLaMA-Factory 微调 Qwen 大模型成功及所有的坑
文章目录 从零安装 LLaMA-Factory 微调 Qwen 大模型成功及所有的坑一 参考二 安装三 启动准备大模型文件 四 数据集(关键)!4.1 Alapaca格式4.2 sharegpt4.3 在 dataset_info.json 中注册4.4 官方 alpaca_zh_demo 例子 999条数据, 本机微调 5分…...
SQL-leetcode—1164. 指定日期的产品价格
1164. 指定日期的产品价格 产品数据表: Products ---------------------- | Column Name | Type | ---------------------- | product_id | int | | new_price | int | | change_date | date | ---------------------- (product_id, change_date) 是此表的主键(具…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...
零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...
免费数学几何作图web平台
光锐软件免费数学工具,maths,数学制图,数学作图,几何作图,几何,AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...
苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会
在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...
解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用
在工业制造领域,无损检测(NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统,以非接触式光学麦克风技术为核心,打破传统检测瓶颈,为半导体、航空航天、汽车制造等行业提供了高灵敏…...
android RelativeLayout布局
<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...
