Java设计模式—观察者模式
观察者模式
目录
- 观察者模式
- 1、什么是观察者模式?
- 2、观察者模式优缺点及注意事项?
- 3、观察者模式实现?
- 4、手写线程安全的观察者模式?
1、什么是观察者模式?
- 实例:现实生活中很多事物都是依赖存在的,一个发生变化会影响很多事物。比如油价上涨,关系很多企业,很多家庭;红绿灯发生变化时,人们会停止,会前进等。
- 观察者模式 (Observer Pattern) :是一种一对多的依赖关系,让多个观察对象同时监听某一个主题对象,当主题对象的状态发生变化时,会自动通知所有观察者,使得它们能够自动更新自己。适用于当一个对象的状态发生改变时,所有依赖于它的对象都需要得到通知的情况。
- 观察者模式具体的角色 :实现观察者模式时要注意具体目标对象和具体观察者对象之间不能直接调用,否则将使两者之间紧密耦合起来,这违反了面向对象的设计原则。
- 抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
- 具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。继承Subject类,在这里实现具体业务,在具体项目中,该类会有很多变种。
- 抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
- 具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。
2、观察者模式优缺点及注意事项?
- 优点:
1.降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系.符合依赖倒置原则
2.目标与观察者之间建立了一套触发机制
- 缺点:
1.目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用
2.当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率
- 注意事项:
1.JDK8 中java.util.Observable 类和 java.util.Observer 接口定义了观察者模式,后面版本舍弃了,因为在使用异步处理的情况下,线程不安全。
2.要注意循环调用情况,避免死锁。
3.可以去观察消息队列实现,典型的观察者模式实现。
3、观察者模式实现?
模仿jdk8中 Observable 类 和 Observer接口实现
- 目标类
public class Subject {private Vector<Observer> obs = new Vector<>();public void addObserver(Observer o) {if (o == null)throw new NullPointerException();if (!obs.contains(o)) {obs.add(o);}}public void deleteObserver(Observer o) {obs.remove(o);}public void notifyObservers() {for(Observer observer : this.obs) {observer.resopnse();}}
}
- 具体实现目标类
public class ConcreteSubject extends Subject{// 具体实现public void doSomethings(){// 一些其它逻辑处理System.out.println("-----被观察者发生了改变------");super.notifyObservers();}
}
- 观察者类
public interface Observer {// 响应void resopnse();
}
- 具体观察者类
public class ConcreteObserver implements Observer{private int num;public ConcreteObserver(int num) {this.num = num;}@Overridepublic void resopnse() {System.out.println("观察者"+num+"做出改变");}
}
- 执行任务
public class Main {public static void main(String[] args) {
// --------------- 观察者模式 -----------------// 先创建多个观察者ConcreteSubject concreteSubject = new ConcreteSubject();for (int a = 0; a < 10; a++) {concreteSubject.addObserver(new ConcreteObserver(a+1));}concreteSubject.doSomethings();}
4、手写线程安全的观察者模式?
设定场景:手机花费快没钱了,运营商通知你要缴费了。 这里运营商就是被观察者,用户就是观察者,用户的手机号就是注册的一个过程,运营商通知用户。
使用jdk中com.util.concurrent提供的线程安全的类:CountDownLatch,CountDownLatch就一个线程同步工具,它相当于一个倒序计数器,用来协调多个线程的执行。多个线程通过调用它们所共享的计数器CountDownLatch的countDown方法来让计数器减1。通过await方法来阻塞当前线程,直到计数器变成0。达到线程阻塞直至其他线程执行完成被重新唤醒。主要有三个方法:
1.构造函数,初始化state的值,state等于同步线程数
2.await(),让线程阻塞
3.countDown(),计数器(state)减1的方法。
public class Main {public static void main(String[] args) {// --------------- 安全的观察者模式 --------------// 设定场景:手机花费快没钱了,运营商通知你要缴费了。 这里运营商就是被观察者,用户就是观察者,用户的手机号就是注册的一个过程,运营商通知用户。ConcreteTelecomOperator telecomOperator = new ConcreteTelecomOperator("中国电信");telecomOperator.addUser(new ConcreteUser("张三"));telecomOperator.addUser(new ConcreteUser("李四"));telecomOperator.addUser(new ConcreteUser("王五"));telecomOperator.addUser(new ConcreteUser("小明"));telecomOperator.doSomeThing("通知您,您已欠费请及时缴费。祝你生活愉快!");}
}
/*** @program: practice_tools* @description: 运营商目标类* @author: tiezhu* @create: 2025-01-20 09:58**/
public class TelecomOperator {private String name;private ConcurrentMap<String, User> obs;public TelecomOperator(String name) {this.name = name;obs = new ConcurrentHashMap<>();}public void addUser(User u){if (u == null)throw new NullPointerException();if (!obs.containsKey(u.getName())) {obs.put(u.getName(),u);}}public void removeUser(User u){obs.remove(u.getName());}public void notifyObservers(String content) {try {long beginTime = System.currentTimeMillis();CountDownLatch latch = new CountDownLatch(obs.size());for (User user : obs.values()) {user.response(content);latch.countDown();}latch.await();long endTime = System.currentTimeMillis();System.out.println(name + "消息发送完毕,耗时:" + (endTime - beginTime));System.out.println();} catch (InterruptedException e) {e.printStackTrace();}}
}
/*** @program: practice_tools* @description: 具体目标类* @author: tiezhu* @create: 2025-01-20 11:43**/
public class ConcreteTelecomOperator extends TelecomOperator{public ConcreteTelecomOperator(String name) {super(name);}public void doSomeThing(String content){System.out.println("开始发布信息:");super.notifyObservers(content);}
}
/*** 用户观察者*/
public interface User {void response(String content);String getName();
}
/*** @program: practice_tools* @description: 观察者实体类* @author: tiezhu* @create: 2025-01-20 10:04**/
public class ConcreteUser implements User{private String name;public ConcreteUser(String name) {this.name = name;}@Overridepublic void response(String content) {System.out.println("接收到了消息为:"+content);System.out.println(name + "准备去缴费了");}@Overridepublic String getName() {return name;}
}
结果:执行结果和创建顺序不同,不用按照创建顺序执行完再执行了。
相关文章:

Java设计模式—观察者模式
观察者模式 目录 观察者模式1、什么是观察者模式?2、观察者模式优缺点及注意事项?3、观察者模式实现?4、手写线程安全的观察者模式? 1、什么是观察者模式? - 实例:现实生活中很多事物都是依赖存在的&#x…...

人工智能在数字化转型中的角色:从数据分析到智能决策
引言 在数字化转型浪潮中,人工智能(AI)正迅速崛起,成为推动企业创新和变革的关键力量。面对日益复杂的市场环境和激烈的行业竞争,企业亟需借助技术手段提高运营效率、优化决策过程,并增强市场竞争力。而AI…...

论文阅读 Multi-view Classification Using Hybrid Fusion and Mutual Distillation
Multi-view Classification Using Hybrid Fusion and Mutual Distillation Intro 多视角问题可以分为两类: Structured。固定视角,或预先定义的视角的问题。unstructured。 本文的三大contributions: 引入了混合的多视角融合策略。使用了…...

AIGC浪潮下,图文内容社区数据指标体系如何构建?
文章目录 01 案例:以图文内容社区为例实践数据指标体构建02 4个步骤实现数据指标体系构建1. 明确业务目标,梳理北极星指标2. 梳理业务流程,明确过程指标3. 指标下钻分级,构建多层级数据指标体系4. 添加分析维度,构建完…...
”彩色的验证码,使用pytesseract识别出来的验证码内容一直是空“的解决办法
问题:彩色的验证码,使用pytesseract识别出来的验证码内容一直是空字符串 原因:pytesseract只识别黑色部分的内容 解决办法:先把彩色图片精确转换成黑白图片。再将黑白图片进行反相,将验证码部分的内容变成黑色&#…...

前端Vue2项目使用md编辑器
项目中有一个需求,要在前端给用户展示内容,内容有 AI 生成的,返回来的是 md 格式,所以需要给用户展示 md 格式,并且管理端也可以编辑这个 md 格式的文档。 使用组件库 v-md-editor。 https://code-farmer-i.github.i…...
OpenVela 架构剖析:从内核到应用
目录 一、总体架构概述 二、 内核层 2.1. OpenVela架构的内核基础 2.2. 内核层的主要职责 2.3. OpenVela对NuttX的扩展与优化 三、系统服务层 2.1. 进程管理 2.2. 内存管理 2.3. 文件系统 2.4. 网络通信 四、框架层 4.1. 模块化设计 4.2. API接口 4.3. 组件和服务…...

vue视频流播放,支持多种视频格式,如rmvb、mkv
先将视频转码为ts ffmpeg -i C:\test\3.rmvb -codec: copy -start_number 0 -hls_time 10 -hls_list_size 0 -f hls C:\test\a\output.m3u8 后端配置接口 import org.springframework.core.io.Resource; import org.springframework.core.io.UrlResource; import org.spring…...
记一个Timestamp时区问题的坑
resultSet.getTimestamp(“kpi_collect_time”)查出来的Timestamp居然是带时区的, 如果该Timestamp不是UTC时区的,Timestamp.toInstant().atZone(ZoneId.of(“UTC”))会把Timestamp转成UTC时区 使用Timestamp.toLocalDateTime()可以直接把时区信息抹除 …...

新年好(Dijkstra+dfs/全排列)
1135. 新年好 - AcWing题库 思路: 1.先预处理出1,a,b,c,d,e到其他点的单源最短路,也就是进行6次Dijkstra 2.计算以1为起点的这6个数的全排列,哪种排列方式所得距离最小,也可以使用dfs 1.Dijkstradfs #define int long longusing …...
如何“看到” Spring 容器?
Spring 容器是一个运行时的抽象工具,用来管理 Bean 的生命周期和依赖。虽然它本身不可直接观察,但可以通过以下方式间接“看到”容器的内容或行为。 2.1 容器是如何实例化的? Spring 容器的实例化是通过 ApplicationContext 或 BeanFactory …...

怎么使用CRM软件?操作方法和技巧有哪些?
什么是CRM? 嘿,大家好!你知道吗,在当今这个数字化时代里,我们每天都在与各种各样的客户打交道。无论是大公司还是小型企业,都希望能够更好地管理这些关系并提高业务效率。这时候就轮到我们的“老朋友”——…...
Spingboot整合Netty,简单示例
Netty介绍在文章末尾 Netty介绍 项目背景 传统socket通信,有需要自身管理整个状态,业务繁杂等问题。 pom.xml <dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.117.F…...

grafana新增email告警
选择一个面板 比如cpu 新增一个临界点表达式 input选A 就是A的值达到某个临界点 触发告警 我这边IS ABOVE0.15就是cpu大于0.15%就触发报警,这个值怎么填看指标的值显示 这里要设置一下报警条件 这边随便配置下 配置标签和通知,选择你的邮件 看下告警…...

Github 2025-01-20 开源项目周报 Top15
根据Github Trendings的统计,本周(2025-01-20统计)共有15个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目10Rust项目2TypeScript项目1C++项目1Jupyter Notebook项目1Go项目1Tabby: 自托管的AI编码助手 创建周期:310 天开发语言:Rust协议类…...

【Rabbitmq】Rabbitmq高级特性-发送者可靠性
Rabbitmq发送者可靠性 发送者重连发送者确认1.开启确认机制2.ReturnCallback3.ConfirmCallback MQ的可靠性数据持久化交换机持久化队列持久化消息持久化 Lazy Queue 总结其他文章 Rabbitmq提供了两种发送来保证发送者的可靠性,第一种叫发送者重连,第二种…...

K8S中Service详解(一)
Service介绍 在Kubernetes中,Service资源解决了Pod IP地址不固定的问题,提供了一种更稳定和可靠的服务访问方式。以下是Service的一些关键特性和工作原理: Service的稳定性:由于Pod可能会因为故障、重启或扩容而获得新的IP地址&a…...
Effective C++读书笔记——item23(用非成员,非友元函数取代成员函数)
一、主要观点: 在某些情况下,使用 non-member、non-friend 函数来替换 member 函数可以增强封装性和可扩展性,提供更好的软件设计。 二、详细解释: 封装性: 类成员函数的封装性考量:成员函数可以访问类的…...
云原生前端开发:打造现代化高性能的用户体验
引言:前端开发的新风向 在过去的几年中,前端开发领域经历了快速的演变,从早期的静态网页到如今复杂的单页应用(SPA),再到微前端架构和渐进式Web应用(PWA),前端技术一直处…...

循环队列(C语言版)
循环队列(C语言版) 1.简单介绍循环队列2.使用何种结构来实现3.基本结构4.初始化5.判空判满6.向循环队列插入一个元素7.从循环队列中删除一个元素8.获取队头队尾元素9.释放空间10.完整代码 🌟🌟hello,各位读者大大们你们好呀&#…...

C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...

Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...