行为型-观察者模式
文章目录
- 基本概念
- 定义
- 使用场景
- 代码实现
- 延伸阅读
- java监听机制
- spring监听机制
基本概念
定义
观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,其所有依赖者都会收到通知并自动更新。
观察者模式(Observer)又称发布-订阅模式(Publish-Subscribe:Pub/Sub)。它是一种通知机制,让发送通知的一方(被观察方)和接收通知的一方(观察者)能彼此分离,互不影响。
观察者模式包含以下几个核心角色:
主题(Subject):也称为被观察者或可观察者,它是具有状态的对象,并维护着一个观察者列表。主题提供了添加、删除和通知观察者的方法。
观察者(Observer):观察者是接收主题通知的对象。观察者需要实现一个更新方法,当收到主题的通知时,调用该方法进行更新操作。
具体主题(Concrete Subject):具体主题是主题的具体实现类。它维护着观察者列表,并在状态发生改变时通知观察者。
具体观察者(Concrete Observer):具体观察者是观察者的具体实现类。它实现了更新方法,定义了在收到主题通知时需要执行的具体操作。
观察者模式通过将主题和观察者解耦,实现了对象之间的松耦合。当主题的状态发生改变时,所有依赖于它的观察者都会收到通知并进行相应的更新。
使用场景
一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。通过这种事件触发的机制,将观察者和被观察者进行解耦。
注意事项:
1、JAVA 中已经有了对观察者模式的支持类。(Java中EventObject、EventListener)
2、避免循环引用。
3、如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。
代码实现
主题接口
/*** 抽象主题(抽象被观察者角色)*/
public interface Subject {/*** 所有抽象观察者角色的集合*/List<Observer> observerList = Lists.newArrayList();/*** 注册观察者* @param observer*/default void addObserver(Observer observer){observerList.add(observer);}/*** 取消注册* @param observer*/default void removeObserver(Observer observer){observerList.remove(observer);}/*** 通知所有观察者* @param content*/default void notifyAllObserver(String content){for (Observer observer: observerList){observer.recvMsg(content);}}}
观察者接口
/*** 观察者*/
public interface Observer {void recvMsg(String content);
}
具体被观察者
@Data
public class ConcreteSubject implements Subject<Observer> {private String msg;/*** 发送通知*/public void sendMsg(){System.out.println("ConcreteSubject send msg: " + this.msg);notifyAllObserver(msg);}
}
具体观察者
public class ConcreteObserver implements Observer {@Overridepublic void recvMsg(String content) {System.out.println("ConcreteObserver recv msg:" + content);}
}
测试
public class ObserverTest {public static void main(String[] args) {ConcreteSubject concreteSubject = new ConcreteSubject();concreteSubject.setMsg("important msg");concreteSubject.addObserver(new ConcreteObserver());concreteSubject.sendMsg();}
}
延伸阅读
java监听机制
一、创建事件对象
public class MusicEvent extends EventObject {public static final int STATE_OPEN = 1;public static final int STATE_CLOSE = -1;/*** 状态*/private int state;/*** Constructs a prototypical Event.** @param source the object on which the Event initially occurred* @throws IllegalArgumentException if source is null*/public MusicEvent(Object source) {super(source);}public MusicEvent(Object source, int state) {super(source);this.state = state;}public int getState() {return state;}public void setState(int state) {this.state = state;}
}
二、创建监听器
public interface MusicListener extends EventListener {void play(MusicEvent musicEvent);
}
CloseMusicListener实现
public class CloseMusicListener implements MusicListener{@Overridepublic void play(MusicEvent musicEvent) {if(musicEvent.getState() == MusicEvent.STATE_CLOSE){System.out.println("CloseMusicListener play: stop dance");}}
}
OpenMusicListener实现
public class OpenMusicListener implements MusicListener{@Overridepublic void play(MusicEvent musicEvent) {if(musicEvent.getState() == MusicEvent.STATE_OPEN){System.out.println("OpenMusicListener play: let us go dancing!");}}
}
三、定义事件源,管理监听器
public class EventSource {// 监听器列表,监听器注册入此列表public List<MusicListener> musicListenerList = new ArrayList<>();// 注册监听器public void addMusicListener(MusicListener musicListener) {musicListenerList.add(musicListener);}// 取消注册public void removeMusicListener(MusicListener musicListener) {musicListenerList.remove(musicListener);}// 接收外部事件public void notifyMusicListener(MusicEvent musicEvent) {for (MusicListener musicListener : musicListenerList){musicListener.play(musicEvent);}}
}
四、测试
public class MusicEventTest {public static void main(String[] args) {EventSource eventSource = new EventSource();eventSource.addMusicListener(new OpenMusicListener());eventSource.addMusicListener(new CloseMusicListener());eventSource.notifyMusicListener(new MusicEvent("开门事件", MusicEvent.STATE_OPEN));}
}
spring监听机制
一、创建事件对象,继承ApplicationEvent
@EqualsAndHashCode(callSuper = true)
public class MyEvent extends ApplicationEvent {private String context;public MyEvent(Object source) {super(source);}public String getContext() {return context;}public void setContext(String context) {this.context = context;}
}
二、定义监听器,实现ApplicationListener
MyApplication1
public class MyApplication1 implements ApplicationListener<MyEvent> {@Overridepublic void onApplicationEvent(MyEvent myEvent) {System.out.println("MyApplication1 event:" + myEvent.getContext());}
}
MyApplication2
public class MyApplication2 implements ApplicationListener<MyEvent> {@Overridepublic void onApplicationEvent(MyEvent myEvent) {System.out.println("MyApplication2 event:" + myEvent.getContext());}
}
三、事件通知
@Service
public class MyListenerService {@Autowiredprivate ApplicationEventPublisher applicationEventPublisher;public void register(MyEvent event){applicationEventPublisher.publishEvent(event);}
}
相关文章:
行为型-观察者模式
文章目录 基本概念定义使用场景代码实现 延伸阅读java监听机制spring监听机制 基本概念 定义 观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,其所有依赖者都会收到通知并自动更新。 观察者模式…...
《ElementPlus 与 ElementUI 差异集合》el-input 和 el-button 属性 size 有变化
差异 ** element-ui el-input、el-input-number 和 el-button 中,属性size 值是 medium / small / minielement-plus el-input、el-input-number 和 el-button 中,属性size 值是 large / default /small 如果你是自动升级,Vue3 系统会有如…...
pxe安装mini centos系统
一、准备工作 1、关闭防火墙和selinux systemctl stop firewalld && systemctl disable firewalldsetenforce 02、配置静态ip 需要在dhcp里面填写tftp配置,所以需要固定ip 二、dhcp安装配置 作用:给客户端提供ip地址,并告诉客户…...
Android studio 性能调试
一、概述 Android studio 的Profiler可用来分析cpu和memory问题,下来进行说明介绍。 二、Android studio CPU调试 从开发模拟器或设备中启动应用程序; 在 Android Studio 中,通过选择View > Tool Windows > Profiler启动分析器。 应…...
java8特性 stream流中map函数的使用
map 函数的作用就是针对管道流中的每一个数据元素进行转换操作。 例如 将集合中的每一个字符串,全部转换成大写! List<String> collect alpha.stream().map(String::toUpperCase).collect(Collectors.toList()); //上面使用了方法引用…...
【Emgu CV教程】9.5、形态学常用操作之形态学梯度
文章目录 一、相关概念1.什么叫形态学梯度2.形态学梯度的函数 二、演示1.原始素材2.代码3.运行结果 一、相关概念 1.什么叫形态学梯度 形态学梯度,就是用膨胀的原始图像减去腐蚀的原始图像,所以它的特性就是去除前景物体的内部区域,只得到前…...
算法笔记之蓝桥杯pat系统备考(2)
算法笔记之蓝桥杯&pat系统备考(1) 文章目录 五、数学问题5.2最大公约数和最小公倍数5.2.1最大公约数5.2.2最小公倍数 5.3分数的四则运算5.3.1分数的表示与化简5.3.2分数的四则运算5.3.3分数的输出 5.4素数(质数)5.4.1[素数的…...
基于SpringBoot+Druid实现多数据源:注解+编程式
前言 本博客姊妹篇 基于SpringBootDruid实现多数据源:原生注解式基于SpringBootDruid实现多数据源:注解编程式基于SpringBootDruid实现多数据源:baomidou多数据源 一、功能描述 配置方式:配置文件中配置默认数据源,…...
已解决org.apache.zookeeper.KeeperException.BadVersionException异常的正确解冲方法,亲测有效!!!
已解决org.apache.zookeeper.KeeperException.BadVersionException异常的正确解冲方法,亲测有效!!! 目录 问题分析 报错原因 解决思路 解决方法 总结 博主v:XiaoMing_Java 问题分析 在使用Apache ZooKeeper进行…...
数据结构:堆
堆的概念 1.堆是一个完全二叉树 2.小堆(任何一个父亲<孩子),大堆(任何一个父亲>孩子) 堆的结构 物理结构:数组 逻辑结构:二叉树 #pragma once #include<assert.h> #include<iostream> typedef int HPDataType; typedef struct Heap {HPDataType* _a;int…...
CSS中三栏布局的实现
三栏布局一般指的是页面中一共有三栏,左右两栏宽度固定,中间自适应的布局,三栏布局的具体实现: 利用绝对定位,左右两栏设置为绝对定位,中间设置对应方向大小的margin的值。 .outer {position: relative;h…...
Linux搭建我的世界(MC)整合包服务器,All the Mods 9(ATM9)整合包开服教程
Linux使用MCSM面板搭建我的世界(Minecraft)整合包服务器,MC开服教程,All the Mods 9(ATM9)整合包搭建服务器的教程。 本教程使用Docker来运行mc服,可以方便切换不同Java版本,方便安装多个mc服版本。 视频教程:https:…...
让数据在业务间高效流转,镜舟科技与NineData完成产品兼容互认
近日,镜舟科技与NineData完成产品兼容测试。在经过联合测试后,镜舟科技旗下产品与NineData云原生智能数据管理平台完全兼容,整体运行高效稳定。 镜舟科技致力于帮助中国企业构建卓越的数据分析系统,打造独具竞争力的“数据护城河”…...
2.1HTML5基本结构
HTML5实际上不算是一种编程语言,而是一种标记语言。HTML5文件是由一系列成对出现的元素标签嵌套组合而成,这些标签以<元素名>的形式出现,用于标记文本内容的含义。浏览器通过元素标签解析文本内容并将结果显示在网页上,而元…...
设置浏览器显示小于12px以下字体
问题 我们在项目开发过程中有时候会遇到设计师给的小于12px的字体,IE、火狐浏览器、移动端等小于12px的字号大小还是可以正常显示的,但是谷歌浏览器上显示字体最小为12px,css设置font-size:10px,运行代码显示结果仍然…...
web蓝桥杯真题:成语学习
代码: //TODO 点击文字后,在idiom从左到右第一个空的位置加上改文字 getSingleWord(val) {let index this.idiom.indexOf() //从左往右查询空字符串this.$set(this.idiom, index, val) //响应式更新 },// TODO 校验成语是否输入正确答案 confirm…...
外包干了5天,技术明显退步。。。。。
先说一下自己的情况,本科生,19年通过校招进入南京某软件公司,干了接近2年的功能测试,今年年初,感觉自己不能够在这样下去了,长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了2年的功能测试&…...
Vue:自定义消息通知组件
一、效果描述 在JS中使用一个Message函数,弹出一个自定义的消息框。 效果体验:缓若江海凝清光 二、实现方式 1.新建一个消息组件 2.新建一个js文件,新建一个需要导出函数 3.在函数中新建一个Vue实例,并将消息组件挂载上去。…...
2023 收入最高的十大编程语言
本期共享的是 —— 地球上目前已知超过 200 种可用的编程语言,了解哪些语言在 2023 为开发者提供更高的薪水至关重要。 过去一年里,我分析了来自地球各地超过 1000 万个开发职位空缺,辅助我们了解市场,以及人气最高和收入最高的语…...
Github 2024-03-11 开源项目周报 Top15
根据Github Trendings的统计,本周(2024-03-11统计)共有15个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目4TypeScript项目3Jupyter Notebook项目3C#项目1HTML项目1CSS项目1Dart项目1Lua项目1Shell项目1Rust…...
铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
边缘计算医疗风险自查APP开发方案
核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...
关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...
处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的
修改bug思路: 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑:async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...
