当前位置: 首页 > news >正文

Java观察者模式

观察者模式有两个对象:

  1. 观察者:Observer
  2. 可被观察者:Observable

比如一个大人要照顾一个小孩子,大人需要时刻观察小孩子,以免发生意外,比如发现小孩子想要横穿马路时要及时拦住,以免被车撞,发现小孩子靠近池塘时要及时拦住, 以免落水。这个大人其实就是一个观察者,而小孩子是一个可被观察者。

当我们需要实现类似这样的功能时,完全可以自己实现观察者可被观察者,但是Java提供了ObserverObservable,使用它们就会更简单,而且大家都用它们,则代码就会更通用。

  • Observer 是一个接口,它就一个update方法,当数据发生变化时就会调用此方法,具体做什么就由我们自己去实现了。
  • Observable不是接口,它是一个类,提供操作观察者的方法,所以我们就不需要去实现这些操作了,直接用就行。

示例如下:

有一个消息列表和一个UI界面,当消息列表中添加了新消息时,我们希望UI界面上显示这个新消息,这里我们就简单一点直接打印这个新消息即可,示例代码如下:

import java.util.Observable
import java.util.Observerclass UI : Observer {override fun update(o: Observable, arg: Any?) {val messageList = o as MessageListprintln("New message: ${messageList.messages.last()}")}
}class MessageList : Observable() {val messages = mutableListOf<String>()fun add(message: String) {messages.add(message)setChanged()notifyObservers()}
}fun main() {val messageList = MessageList()val ui = UI()messageList.addObserver(ui)messageList.add("Hello")// 当不再需要观察时messageList.deleteObserver(ui)
}

如上代码,当我们往messageList中添加一个消息时,UI就会得到通知,具体就是UI的update方法被调用。

Observable类的功能非常简单的,看一下它的源代码实现即可了解其原理。

通知观察者时,还可以带一个参数,比如我们对消息列表有增、删、改、查的操作,我们想让观察者知道我们是一个什么样的操作,就可以在通知的时候添加参数,比如通知添加了一个消息:

class UI : Observer {override fun update(o: Observable, arg: Any?) {val messageList = o as MessageListprintln("消息列表发生了${arg}操作:${messageList.messages.last()}")}
}class MessageList : Observable() {val messages = mutableListOf<String>()fun add(message: String) {messages.add(message)setChanged()notifyObservers("add")}
}fun main() {val messageList = MessageList()val ui = UI()messageList.addObserver(ui)messageList.add("Hello")
}

运行结果为:

消息列表发生了add操作:Hello

自Java 9开始,ObserverObservable被标记为过时,主要原因是其设计存在一些局限性,例如事件模型不够丰富、无法序列化、以及线程安全问题等。我们可以使用比如PropertyChangeSupportRxJava / ReactorLiveData (Android)​等做为代替,其中PropertyChangeSupport是JDK自带,无需额外依赖,PropertyChangeSupportJava Beans 规范的一部分,它通过 ​​"属性变更事件"​​ 来工作,非常适用于基于状态的变更通知。示例如下:

import java.beans.PropertyChangeEvent
import java.beans.PropertyChangeListener
import java.beans.PropertyChangeSupportclass MessageList {// 持有 PropertyChangeSupport 实例private val pcs = PropertyChangeSupport(this)val messages = mutableListOf<String>()// 添加观察者fun addPropertyChangeListener(listener: PropertyChangeListener) {pcs.addPropertyChangeListener(listener)}// 移除观察者fun removePropertyChangeListener(listener: PropertyChangeListener) {pcs.removePropertyChangeListener(listener)}fun add(message: String) {val oldValue = messages.size // 可以传递旧值,这里简单用大小示意messages.add(message)// 触发通知,传递属性名、旧值和新值pcs.firePropertyChange("messages", oldValue, messages.size)// 也可以触发一个更泛化的事件,比如只通知“列表变了”// pcs.firePropertyChange("messageAdded", null, message)}
}class UI : PropertyChangeListener {override fun propertyChange(evt: PropertyChangeEvent) {// 根据属性名判断发生了什么变化when (evt.propertyName) {"messages" -> println("消息列表发生了变化:新增了消息,当前总数 ${evt.newValue}")// 可以处理其他属性...}// 如果 fire 的是具体消息// println("消息列表新增了:${evt.newValue}")}
}fun main() {val messageList = MessageList()val ui = UI()messageList.addPropertyChangeListener(ui)messageList.add("Hello")
}

当我们想学习RxJava的时候,最好先学习一下Java中的ObserverObservable的使用。


文章转载自:

http://c1mfTfvu.sLtry.cn
http://o1oVCJwQ.sLtry.cn
http://mSuOB8By.sLtry.cn
http://H55UqPAS.sLtry.cn
http://yLvs3zzq.sLtry.cn
http://ZMKyp1NX.sLtry.cn
http://PG8KY4aR.sLtry.cn
http://ak1wSM27.sLtry.cn
http://BwgXBu9f.sLtry.cn
http://nEOY3CPC.sLtry.cn
http://iZzIraDq.sLtry.cn
http://5Xyl4RL8.sLtry.cn
http://Rw26hTVN.sLtry.cn
http://amFFK9BQ.sLtry.cn
http://UMHrjnCl.sLtry.cn
http://6Xj346nS.sLtry.cn
http://XMM0s0Mw.sLtry.cn
http://34Q2eQrY.sLtry.cn
http://on8RbG7F.sLtry.cn
http://zJxx1DcH.sLtry.cn
http://kI3vqfHx.sLtry.cn
http://60IvhFDl.sLtry.cn
http://4EzuLHZT.sLtry.cn
http://Tx7DFHrf.sLtry.cn
http://9uy2buSy.sLtry.cn
http://riUAGI1w.sLtry.cn
http://A8ql5Rwi.sLtry.cn
http://DIHJK8v1.sLtry.cn
http://NLhQrnfZ.sLtry.cn
http://E8yYdbXB.sLtry.cn
http://www.dtcms.com/a/368444.html

相关文章:

  • 深度学习从入门到精通 - BERT与预训练模型:NLP领域的核弹级技术详解
  • DeepSeek:开启智能体驱动对话式数据分析新时代
  • 分布式3PC理论
  • 在本地使用Node.js和Express框架来连接和操作远程数据库
  • Linux应用(2)——标准IO
  • 面试官问:你选择这份工作的动机是什么?
  • 大型语言模型SEO(LLM SEO)完全手册:驾驭搜索新范式
  • Onlyoffice集成与AI交互操作指引(Iframe版)
  • 前端视觉交互设计全解析:从悬停高亮到多维交互体系(含代码 + 图表)
  • 【基础组件】手撕 MYSQL 连接池(C++ 版本)
  • 【FastDDS】Layer Transport ( 01-overview )
  • 算法备案全流程-纯干货
  • Linux 进程信号的产生
  • 【华为Mate XTs 非凡大师】麒麟芯片回归:Mate XTs搭载麒麟9020,鸿蒙5.1体验新境界
  • Swift 解题:LeetCode 372 超级次方(Super Pow)
  • 深入理解 JVM 字节码文件:从组成结构到 Arthas 工具实践
  • C# 阿里云 OSS 图片上传步骤及浏览器查看方法
  • JVM新生代和老生代比例如何设置?
  • 基于OpenGL封装摄像机类:视图矩阵与透视矩阵的实现
  • MySQL 8.0.36 主从复制完整实验
  • 无需bootloader,BootROM -> Linux Kernel 启动模式
  • 【Vue3+TypeScript】H5项目实现企业微信OAuth2.0授权登录完整指南
  • 为什么MySQL可重复读级别不能完全避免幻读
  • Gradle Task 进阶:Task 依赖关系、输入输出、增量构建原理
  • 串口通信基础知识
  • webshell及冰蝎双击无法打开?
  • Doris 数据仓库例子
  • 从零构建企业级LLMOps平台:LMForge——支持多模型、可视化编排、知识库与安全审核的全栈解决方案
  • 如何根据Excel数据表生成多个合同、工作证、录取通知书等word文件?
  • Highcharts 数据源常见问题解析:连接方式、格式处理与性能优化指南