在Java中如何实现观察者模式_JavaObserverPattern对象交互解析

发布时间 - 2026-02-02 00:00:00    点击率:
Java原生Observer/Observable因继承限制和弃用已不推荐,应手写接口+Subject抽象类实现解耦观察者模式,配合CopyOnWriteArrayList保障线程安全,并可选用Spring@EventListener替代。

Java里用 ObserverObservable 类写观察者模式为什么总不生效

因为 java.util.Observable 是抽象类,且从 Java 9 开始被标记为 @Deprecated,JDK 官方明确不再推荐使用。更关键的是:它要求被观察者必须继承 Observable,而 Java 不支持多重继承,一旦你的类已继承其他父类(比如 Thread 或某个业务基类),这条路就走不通。

实际开发中几乎没人用这套原生 API,真正稳定、灵活的方案是手写接口 + 自定义通知逻辑。

自己定义 Observer 接口和 Subject 抽象类更可靠

核心是解耦:观察者只关心“被通知”,不依赖具体被观察者类型;被观察者只维护观察者列表,不绑定任何实现细节。

  • Observer 接口定义 update(Subject subject, Object data) 方法,接收通知源和数据
  • Subject 抽象类提供 addObserver()removeObserver()notifyObservers() 基础能力
  • 具体被观察者(如 WeatherStation)继承 Subject,在状态变化时调用 notifyObservers(this, currentData)
  • 具体观察者(如 PhoneDisplay)实现 Observer,在 update() 中处理业务逻辑

这样既避免继承限制,又支持泛型扩展(比如让 update() 接收 Event 类型参数)。

java.util.concurrent.CopyOnWriteArrayList 存储观察者列表

多线程环境下,遍历观察者列表的同时可能有其他线程在增删监听器——直接用 ArrayList 会触发 ConcurrentModificationException

CopyOnWriteArrayList 的行为特点是:

  • 读操作无锁、高性能,适合频繁通知场景
  • 写操作(add/remove)会复制整个数组,适合观察者数量少、变更不频繁的情况
  • 通知时遍历的是快照,不会因中途修改导致异常或漏通知
public abstract class Subject {
    private final List observers = new CopyOnWriteArrayList<>();

    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    public void notifyObservers(

Object data) { for (Observer o : observers) { o.update(this, data); } } }

Spring 的 @EventListener 是观察者模式的高级替代方案

如果你项目已引入 Spring,没必要重复造轮子。Spring 的事件机制本质就是观察者模式的生产级实现:

  • 发布事件用 ApplicationEventPublisher.publishEvent(new CustomEvent(source, data))
  • 监听事件只需一个带 @EventListener 的方法,参数类型即事件类型
  • 天然支持异步(加 @Async)、事务绑定(@TransactionalEventListener)、条件过滤(condition = "#event.status == 'OK'"
  • 所有监听器自动注册到容器,无需手动管理生命周期

注意:自定义事件类必须继承 ApplicationEvent,否则 Spring 不识别;非 Spring 环境下该方案不可用。

手写观察者最易忽略的点是状态同步时机——不是“只要变了就立刻通知”,而是要判断是否真的需要广播(比如连续三次温度更新只差 0.1℃,应合并或节流)。这层逻辑得由具体业务决定,框架只管“怎么发”,不管“什么时候发”。


# java  # app  # 无锁  # 为什么  # spring  # Object  # 父类  # 继承  # 接口  # 多重继承  # Event  # 泛型  # 线程  # 多线程  # Thread  # 对象  # 事件  # this  # 异步  # 的是  # 抽象类  # 遍历  # 自定义  # 绑定  # 如果你  # 什么时候  # 只需  # 没人  # 推荐使用 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 用yum安装MySQLdb模块的步骤方法  微信小程序 require机制详解及实例代码  浅谈redis在项目中的应用  如何在IIS中新建站点并解决端口绑定冲突?  香港服务器建站指南:外贸独立站搭建与跨境电商配置流程  南京网站制作费用,南京远驱官方网站?  用v-html解决Vue.js渲染中html标签不被解析的问题  非常酷的网站设计制作软件,酷培ai教育官方网站?  免费制作统计图的网站有哪些,如何看待现如今年轻人买房难的情况?  制作企业网站建设方案,怎样建设一个公司网站?  Laravel如何实现API速率限制?(Rate Limiting教程)  iOS中将个别页面强制横屏其他页面竖屏  手机怎么制作网站教程步骤,手机怎么做自己的网页链接?  Laravel项目如何进行性能优化_Laravel应用性能分析与优化技巧大全  如何用PHP工具快速搭建高效网站?  专业型网站制作公司有哪些,我设计专业的,谁给推荐几个设计师兼职类的网站?  百度浏览器ai对话怎么关 百度浏览器ai聊天窗口隐藏  香港服务器建站指南:免备案优势与SEO优化技巧全解析  Windows11怎样设置电源计划_Windows11电源计划调整攻略【指南】  Python文件操作最佳实践_稳定性说明【指导】  Laravel如何实现本地化和多语言支持?(i18n教程)  Laravel如何使用Guzzle调用外部接口_Laravel发起HTTP请求与JSON数据解析【详解】  如何用搬瓦工VPS快速搭建个人网站?  JavaScript如何实现错误处理_try...catch如何捕获异常?  合肥制作网站的公司有哪些,合肥聚美网络科技有限公司介绍?  如何在宝塔面板中修改默认建站目录?  Laravel Eloquent性能优化技巧_Laravel N+1查询问题解决  Laravel如何实现模型的全局作用域?(Global Scope示例)  Laravel如何使用Collections进行数据处理?(实用方法示例)  如何基于云服务器快速搭建个人网站?  Python函数文档自动校验_规范解析【教程】  Laravel Eloquent:优雅地将关联模型字段扁平化到主模型中  如何快速查询域名建站关键信息?  Laravel如何处理文件下载请求?(Response示例)  JavaScript模板引擎Template.js使用详解  家族网站制作贴纸教程视频,用豆子做粘帖画怎么制作?  大连 网站制作,大连天途有线官网?  品牌网站制作公司有哪些,买正品品牌一般去哪个网站买?  Laravel怎么使用artisan命令缓存配置和视图  网站制作大概多少钱一个,做一个平台网站大概多少钱?  MySQL查询结果复制到新表的方法(更新、插入)  HTML5空格和margin有啥区别_空格与外边距的使用场景【说明】  北京网站制作的公司有哪些,北京白云观官方网站?  php静态变量怎么调试_php静态变量作用域调试技巧【解答】  Python结构化数据采集_字段抽取解析【教程】  如何用免费手机建站系统零基础打造专业网站?  韩国服务器如何优化跨境访问实现高效连接?  Laravel如何获取当前登录用户信息_Laravel Auth门面使用与Session用户读取【技巧】  Python面向对象测试方法_mock解析【教程】  Laravel如何发送系统通知_Laravel Notifications实现多渠道消息通知