深度剖析观察者模式:从理论到实战的Java实现

news2025/2/13 5:27:17

在软件设计中,观察者模式(Observer Pattern) 是一种高频使用的行为型设计模式,它定义了对象之间一对多的依赖关系,使得当一个对象状态改变时,其所有依赖对象(观察者)会自动收到通知并更新。这种模式在事件驱动系统、GUI框架、实时数据处理等领域应用广泛。本文将从模式原理、Java实现、应用场景、源码级优化等角度,深度剖析观察者模式的设计哲学与实践技巧。

一、观察者模式的核心思想

观察者模式的核心是解耦被观察者(Subject)与观察者(Observer),其设计目标包括:

  1. 动态订阅与取消订阅:观察者可以灵活注册或解除对主题的关注。

  2. 状态同步:主题状态变化时,所有观察者能自动响应。

  3. 松耦合:主题无需知道观察者的具体实现细节,仅依赖抽象接口。

模式角色划分
  • Subject(主题):维护观察者列表,提供注册、注销和通知方法。

  • ConcreteSubject(具体主题):实现Subject,存储状态,并在状态变化时触发通知。

  • Observer(观察者):定义更新接口,供主题调用。

  • ConcreteObserver(具体观察者):实现Observer接口,执行具体业务逻辑。


二、Java实现观察者模式:原生支持与自定义实现

1. Java内置观察者模式(java.util.Observable)

Java早期通过 Observable 类和 Observer 接口提供了观察者模式的原生支持,但因其设计缺陷(如Observable是类而非接口),在Java 9后被标记为废弃。以下是经典实现:

// 被观察者(继承Observable)
public class WeatherStation extends Observable {
    private float temperature;

    public void setTemperature(float temperature) {
        this.temperature = temperature;
        setChanged();    // 标记状态变化
        notifyObservers(temperature); // 通知观察者(可传递数据)
    }
}

// 观察者(实现Observer接口)
public class Display implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        if (o instanceof WeatherStation) {
            System.out.println("温度更新: " + arg + "°C");
        }
    }
}

// 使用示例
public class Client {
    public static void main(String[] args) {
        WeatherStation station = new WeatherStation();
        Display display = new Display();
        station.addObserver(display);
        station.setTemperature(25.5f); // 触发通知
    }
}
2. 自定义观察者模式实现(推荐)

为避免Java内置实现的局限性,可自定义观察者模式:

// 主题接口
public interface Subject<T> {
    void registerObserver(Observer<T> observer);
    void removeObserver(Observer<T> observer);
    void notifyObservers(T data);
}

// 具体主题
public class WeatherStation implements Subject<Float> {
    private List<Observer<Float>> observers = new ArrayList<>();
    private float temperature;

    @Override
    public void registerObserver(Observer<Float> observer) {
        observers.add(observer);
    }

    @Override
    public void notifyObservers(Float data) {
        observers.forEach(observer -> observer.update(data));
    }

    public void setTemperature(float temperature) {
        this.temperature = temperature;
        notifyObservers(temperature);
    }
}

// 观察者接口(泛型支持)
public interface Observer<T> {
    void update(T data);
}

// 具体观察者
public class Display implements Observer<Float> {
    @Override
    public void update(Float temperature) {
        System.out.println("[Display] 当前温度: " + temperature);
    }
}

优势分析

  • 类型安全:通过泛型避免强制类型转换。

  • 灵活性:Subject和Observer接口可自由扩展。

  • 解耦彻底:不依赖Java废弃类。


三、观察者模式的进阶应用与优化

1. 异步通知机制

在高并发场景中,同步通知可能阻塞主题线程。可通过线程池实现异步通知:

// 在Subject实现类中注入线程池
private ExecutorService executor = Executors.newCachedThreadPool();

public void notifyObservers(T data) {
    observers.forEach(observer -> 
        executor.submit(() -> observer.update(data))
    );
}
2. 防止观察者阻塞

若某个观察者处理时间过长,可能影响整体性能。可引入超时机制熔断策略

3. 观察者链与责任传递

观察者可形成责任链,在链中传递事件,直至被处理(类似事件冒泡)。


四、观察者模式的典型应用场景

1. GUI事件监听

例如Java Swing中的ActionListener,Android的OnClickListener

2. 分布式系统消息队列

如Kafka的生产者-消费者模型,本质是观察者模式的扩展。

3. Spring框架的事件机制

Spring的ApplicationEventApplicationListener实现了观察者模式,支持应用内事件驱动编程。

// 自定义事件
public class OrderEvent extends ApplicationEvent {
    public OrderEvent(Object source, String message) {
        super(source);
        this.message = message;
    }
}

// 监听器
@Component
public class OrderListener implements ApplicationListener<OrderEvent> {
    @Override
    public void onApplicationEvent(OrderEvent event) {
        System.out.println("收到订单事件: " + event.getMessage());
    }
}

// 发布事件
applicationContext.publishEvent(new OrderEvent(this, "订单创建成功"));

五、观察者模式的优缺点与替代方案

优点
  • 符合开闭原则:新增观察者无需修改主题代码。

  • 动态建立对象间关系。

缺点
  • 通知顺序不可控:观察者接收通知的顺序不确定。

  • 循环依赖风险:观察者与主题相互引用可能导致内存泄漏。

替代方案
  • 发布-订阅模式:通过中间代理(如消息队列)彻底解耦生产者和消费者。

  • 响应式编程:如RxJava、Project Reactor,提供更强大的流处理能力。


六、总结

观察者模式是事件驱动架构的基石,其核心在于构建灵活、松耦合的交互系统。在Java生态中,无论是传统GUI开发,还是现代Spring框架、响应式编程,观察者模式的身影无处不在。开发者需根据场景选择合适实现方式,并注意线程安全、性能优化等关键问题。理解观察者模式,是掌握高扩展性系统设计的重要一步

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2297167.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Rust学习总结之所有权(一)

不管是计算机的哪种语言&#xff0c;都有内存的管理方式。主流有两种&#xff0c;一是以C为代表的由开发者来决定申请和释放内存&#xff0c;二是以Python为代表的通过语言本身的垃圾回收机制来自动管理内存。Rust开辟了第三种方式&#xff0c;通过所有权系统管理内存。 Rust所…

汇编简介常用语法

为什么要有汇编 因为Cortex-A芯片一上电SP指针还没初始化&#xff0c;C环境还没准备 好&#xff0c;所以肯定不能运行C代码&#xff0c;必须先用汇编语言设置好C环境&#xff0c;比如初始化DDR、设置SP 指针等等&#xff0c;当汇编把C环境设置好了以后才可以运行C代码 GNU语法…

ANR学习

一、ANR 概述 ANR 是 Android 系统用于监控应用是否及时响应的关键机制。形象地说&#xff0c;如同设置定时炸弹场景&#xff1a;系统的中控系统&#xff08;system_server 进程&#xff09;启动倒计时&#xff0c;若应用进程在规定时间内未完成特定任务&#xff0c;中控系统将…

Tcp_socket

Tcp不保证报文完整性&#xff08;面向字节流&#xff09; 所以我们需要在应用层指定协议&#xff0c;确保报文完整性 // {json} -> len\r\n{json}\r\n bool Encode(std::string &message) {if(message.size() 0) return false;std::string package std::to_string(m…

< 自用文儿 > 在 Ubuntu 24 卸载 Docker 应用软件与运行的容器

环境&#xff1a; Host: usw OS: Ubuntu 24.04 TLS 目标: 卸载在运行的 Docker APP。 &#xff08;上运行了一个 container: 可以在线看 WSJ RSS 新闻&#xff0c;都 docker 预装两个网口&#xff0c;今天发现路由表有些看不懂&#xff0c;决定卸载&#xff09; 卸载 Dock…

基于 SpringBoot 和 Vue 的智能腰带健康监测数据可视化平台开发(文末联系,整套资料提供)

基于 SpringBoot 和 Vue 的智能腰带健康监测数据可视化平台开发 一、系统介绍 随着人们生活水平的提高和健康意识的增强&#xff0c;智能健康监测设备越来越受到关注。智能腰带作为一种新型的健康监测设备&#xff0c;能够实时采集用户的腰部健康数据&#xff0c;如姿势、运动…

Python的那些事第十八篇:框架与算法应用研究,人工智能与机器学习

人工智能与机器学习&#xff1a;框架与算法应用研究 摘要 本文深入探讨了人工智能与机器学习领域的核心框架和技术&#xff0c;包括TensorFlow、PyTorch和Scikit-learn库。文章首先介绍了TensorFlow和PyTorch的安装与配置方法&#xff0c;详细阐述了它们的基础概念&#xff0c…

java微服务常用技术

Spring Cloud Alibaba 1 系统架构演进 随着互联网行业的发展,对服务的要求也越来越高,服务架构也从单体架构逐渐演变为现在流行的微服务架构。 1.1 单体架构 早期的软件系统通常是基于单体应用架构设计的,也就是将整个系统作为一个单一的、可执行的应用程序来构建和维护…

【Qt 常用控件】多元素控件(QListWidget、QTabelWidgt、QTreeWidget)

**View和**Widget的区别&#xff1f; **View的实现更底层&#xff0c;**Widget是基于**View封装实现的更易用的类型。 **View使用MVC结构 MVC是软件开发中 经典的 软件结构 组织形式&#xff0c;软件设计模式。 M&#xff08;model&#xff09;模型。管理应用程序的核心数据和…

解决VsCode的 Vetur 插件has no default export Vetur问题

文章目录 前言1.问题2. 原因3. 解决其他 前言 提示&#xff1a; 1.问题 Cannot find module ‘ant-design-vue’. Did you mean to set the ‘moduleResolution’ option to ‘node’, or to add aliases to the ‘paths’ option? Module ‘“/xxx/xxx/xxx/xxx/xxx/src/vie…

python制作自己的一款Markdowm格式消除工具

01 引言 在日常使用 Markdown 编写文档时&#xff0c;我们有时会需要将 Markdown 格式的文本转换为纯文本&#xff0c;去除其中的各种标记符号&#xff0c;如标题符号、列表符号、代码块标记等。手动去除这些标记不仅效率低下&#xff0c;还容易出错。本文将介绍如何使用 Pyt…

如何从头训练大语言模型: A simple technical report

今天来快速捋一下路线&#xff0c;写个简短的technical report&#xff0c;更多是原理介绍性的。按我个人理解&#xff0c;从最简单的部分开始&#xff0c;逐步过渡到最繁复的环节: 模型架构-> Pretrain -> Post-Train -> Infra -> 数据侧。再掺杂一些杂项&#xf…

gitlab无法登录问题

在我第一次安装gitlab的时候发现登录页面是 正常的页面应该是 这种情况的主要原因是不是第一次登录&#xff0c;所以我们要找到原先的密码 解决方式&#xff1a; [rootgitlab ~]# vim /etc/gitlab/initial_root_password# WARNING: This value is valid only in the followin…

食品饮料生产瓶颈?富唯智能协作机器人来 “破壁”

在食品和饮料行业的发展进程中&#xff0c;诸多生产瓶颈如重复性劳动负担、复杂环境作业难题、季节性产能波动等&#xff0c;长期制约着企业的高效运营与进一步发展。如今&#xff0c;富唯智能协作机器人的出现&#xff0c;为这些难题提供了完美的解决方案&#xff0c;正逐步改…

Python 实现 macOS 系统代理的设置

设置 SOCKS 代理 在 macOS 系统中&#xff0c;可以通过 networksetup 工具来设置 SOCKS 代理。以下是 Python 实现的方法&#xff1a; 使用 networksetup 设置 SOCKS 代理 import subprocessdef set_socks_proxy(server, port):"""设置 macOS 系统的 SOCKS 代理…

深度学习之神经网络框架搭建及模型优化

神经网络框架搭建及模型优化 目录 神经网络框架搭建及模型优化1 数据及配置1.1 配置1.2 数据1.3 函数导入1.4 数据函数1.5 数据打包 2 神经网络框架搭建2.1 框架确认2.2 函数搭建2.3 框架上传 3 模型优化3.1 函数理解3.2 训练模型和测试模型代码 4 最终代码测试4.1 SGD优化算法…

【设计模式】【行为型模式】命令模式(Command)

&#x1f44b;hi&#xff0c;我不是一名外包公司的员工&#xff0c;也不会偷吃茶水间的零食&#xff0c;我的梦想是能写高端CRUD &#x1f525; 2025本人正在沉淀中… 博客更新速度 &#x1f4eb; 欢迎V&#xff1a; flzjcsg2&#xff0c;我们共同讨论Java深渊的奥秘 &#x1f…

C++模拟实现AVL树

目录 1.文章概括 2.AVL树概念 3.AVL树的性质 4.AVL树的插入 5.旋转控制 1.左单旋 2. 右单旋 3.左右双旋 4.右左双旋 6.全部代码 1.文章概括 本文适合理解平衡二叉树的读者阅读&#xff0c;因为AVL树是平衡二叉树的一种优化&#xff0c;其大部分实现逻辑与平衡二叉树是…

python卷积神经网络人脸识别示例实现详解

目录 一、准备 1&#xff09;使用pytorch 2&#xff09;安装pytorch 3&#xff09;准备训练和测试资源 二、卷积神经网络的基本结构 三、代码实现 1&#xff09;导入库 2&#xff09;数据预处理 3&#xff09;加载数据 4&#xff09;构建一个卷积神经网络 5&#xff0…

以Unity6.0为例,如何在Unity中开启DLSS功能

DLSS DLSS&#xff08;NVIDIA 深度学习超级采样&#xff09;&#xff1a;NVIDIA DLSS 是一套由 GeForce RTX™ Tensor Core 提供支持的神经渲染技术&#xff0c;可提高帧率&#xff0c;同时提供可与原生分辨率相媲美的清晰、高质量图像。目前最新突破DLSS 4 带来了新的多帧…