java23种设计模式-观察者模式

news/2025/2/27 10:37:43

观察者模式(Observer Pattern)学习笔记


编程相关书籍分享:https://blog.csdn.net/weixin_47763579/article/details/145855793
DeepSeek使用技巧pdf资料分享:https://blog.csdn.net/weixin_47763579/article/details/145884039


1. 模式定义

行为型设计模式,定义对象间的一种一对多依赖关系,当一个对象状态发生改变时,所有依赖它的对象都会得到通知并自动更新。又称为发布-订阅模式。

2. 适用场景

✅ 需要实现事件触发机制
✅ 存在多个对象依赖一个对象状态的场景
✅ 需要实现广播通信机制
✅ 需要解耦观察者与被观察者
✅ 需要动态增减观察者对象

3. 模式结构

notifies
«interface»
Subject
+registerObserver()
+removeObserver()
+notifyObservers()
«interface»
Observer
+update()
ConcreteSubject
-state
-observers: List
+getState()
+setState()
ConcreteObserverA
+update()
ConcreteObserverB
+update()

4. 核心角色

角色说明
Subject抽象主题(被观察者),定义注册、删除、通知观察者的接口
ConcreteSubject具体主题,维护观察者列表,状态改变时通知所有观察者
Observer抽象观察者,定义更新接口
ConcreteObserver具体观察者,实现更新逻辑

5. 代码示例

5.1 气象站监控示例

// 抽象主题
interface WeatherSubject {
    void registerObserver(WeatherObserver o);
    void removeObserver(WeatherObserver o);
    void notifyObservers();
}

// 具体主题
class WeatherStation implements WeatherSubject {
    private List<WeatherObserver> observers = new ArrayList<>();
    private float temperature;
    private float humidity;
    
    public void setMeasurements(float temp, float humidity) {
        this.temperature = temp;
        this.humidity = humidity;
        notifyObservers();
    }
    
    public void registerObserver(WeatherObserver o) {
        observers.add(o);
    }
    
    public void removeObserver(WeatherObserver o) {
        observers.remove(o);
    }
    
    public void notifyObservers() {
        for (WeatherObserver o : observers) {
            o.update(temperature, humidity);
        }
    }
}

// 抽象观察者
interface WeatherObserver {
    void update(float temp, float humidity);
}

// 具体观察者
class CurrentConditionsDisplay implements WeatherObserver {
    public void update(float temp, float humidity) {
        System.out.printf("当前天气状况:温度%.1f℃ 湿度%.1f%%\n", temp, humidity);
    }
}

class StatisticsDisplay implements WeatherObserver {
    public void update(float temp, float humidity) {
        // 实现统计逻辑
        System.out.println("更新统计数据显示...");
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        WeatherStation station = new WeatherStation();
        WeatherObserver currentDisplay = new CurrentConditionsDisplay();
        WeatherObserver statisticsDisplay = new StatisticsDisplay();
        
        station.registerObserver(currentDisplay);
        station.registerObserver(statisticsDisplay);
        
        station.setMeasurements(25.5f, 65.0f);
        /* 输出:
           当前天气状况:温度25.5℃ 湿度65.0%
           更新统计数据显示... */
    }
}

6. 模式变种

6.1 推拉模型对比

模型类型数据传递方式特点
主题主动发送完整数据给观察者观察者被动接收,可能收到不需要的数据
观察者主动从主题获取所需数据需要时获取,减少不必要数据传输
// 拉模型实现示例
interface PullObserver {
    void update(WeatherSubject subject);
}

class PullWeatherDisplay implements PullObserver {
    public void update(WeatherSubject subject) {
        if (subject instanceof WeatherStation) {
            WeatherStation ws = (WeatherStation)subject;
            System.out.println("温度:" + ws.getTemperature());
        }
    }
}

7. 优缺点分析

✔️ 优点

  • 实现松耦合
  • 支持动态添加/删除观察者
  • 符合开闭原则
  • 支持广播通信

缺点

  • 通知顺序不可控
  • 观察者过多时影响性能
  • 循环依赖可能导致系统崩溃
  • 观察者可能收到不相关通知

8. 相关模式对比

模式目的关键区别
发布-订阅模式消息通知机制通过消息代理解耦,支持更复杂路由
中介者模式对象间交互集中控制通信,观察者模式是分布式通知
责任链模式请求传递观察者模式是单向通知机制

9. 实际应用案例

  • Java Swing的事件监听机制(ActionListener
  • Spring框架的ApplicationEventApplicationListener
  • Android的BroadcastReceiver
  • JavaBeans的PropertyChangeListener
  • Reactor编程模型
  • Vue.js的响应式系统
  • Kafka消息队列

10. 最佳实践建议

  1. 使用Java内置实现
// Java 9之前可用(已过时)
import java.util.Observable;
import java.util.Observer;

// Java 9+推荐使用PropertyChangeSupport
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
  1. 防止内存泄漏
// 及时移除观察者
subject.addObserver(observer);
// ...
subject.deleteObserver(observer);
  1. 异步通知优化
// 使用线程池异步通知
ExecutorService executor = Executors.newCachedThreadPool();
public void notifyObservers() {
    for (Observer o : observers) {
        executor.submit(() -> o.update(data));
    }
}
  1. 使用弱引用(WeakReference):
// 防止观察者无法被垃圾回收
List<WeakReference<Observer>> weakObservers = new ArrayList<>();

public void registerObserver(Observer o) {
    weakObservers.add(new WeakReference<>(o));
}
  1. 事件过滤机制
// 添加事件类型过滤
interface EventObserver {
    void update(EventType type, Object data);
}

enum EventType { TEMP_CHANGE, HUMIDITY_CHANGE }

11. 扩展应用(Spring事件机制)

// 自定义事件
public class OrderCreatedEvent extends ApplicationEvent {
    private Order order;
    public OrderCreatedEvent(Object source, Order order) {
        super(source);
        this.order = order;
    }
    // getter...
}

// 事件发布者
@Service
class OrderService {
    @Autowired
    private ApplicationEventPublisher publisher;
    
    public void createOrder(Order order) {
        // 创建订单逻辑...
        publisher.publishEvent(new OrderCreatedEvent(this, order));
    }
}

// 事件监听者
@Component
class NotificationService {
    @EventListener
    public void handleOrderCreated(OrderCreatedEvent event) {
        // 发送通知逻辑...
    }
}

🔍 设计原则体现

  1. 开闭原则(OCP):新增观察者无需修改主题
  2. 松耦合原则:主题与观察者互相不知道对方细节
  3. 单一职责原则:主题管理状态,观察者处理通知

通过观察者模式,可以实现高效的事件通知机制,特别适合需要实现实时数据同步、事件驱动架构的场景。该模式在GUI开发、分布式系统和框架设计中应用广泛,是解耦组件关系的经典解决方案。


http://www.niftyadmin.cn/n/5869961.html

相关文章

u3d使用图片字/渐变色字/艺术字详解

一.使用BMFont生成.fnt和.tga文件 1.1 下载安装bmfont Bitmap Font Generator 1.2 设置bit depth为32位 Options->Export options 1.3 清理选择字符 Edit->Clear all chars in fomt 1.4 导入艺术字图片 Edit->Open Image Manager Image->Import image 选择美术…

本地部署阿里的万象2.1文生视频(Wan2.1-T2V-1.3B)模型

文章目录 &#xff08;零&#xff09;在线体验&#xff08;一&#xff09;本地部署&#xff08;1.1&#xff09;克隆仓库&#xff08;1.2&#xff09;安装依赖&#xff08;1.2.1&#xff09;安装 flash-attention&#xff08;1.2.2&#xff09;重新安装依赖&#xff08;1.2.3&a…

深入理解高阶函数:提升JavaScript编程技巧

在JavaScript中&#xff0c;函数是一等公民&#xff0c;这意味着函数可以像其他数据类型一样被传递、赋值和返回。高阶函数&#xff08;Higher-Order Function&#xff09;是函数式编程中的一个核心概念&#xff0c;它能够极大地提升代码的灵活性和可重用性。本文将深入探讨高阶…

Nuxt.js 3【详解】敏感信息处理 -- 环境变量配置

部分敏感信息不便存在代码中&#xff0c;需在环境变量中配置 新建 .env NUXT_API_KEY123以 apiKey 为例&#xff0c;在 .env 中&#xff0c;必须以 NUXT_ 开头&#xff0c;全部大写&#xff0c;驼峰用 _连接 nuxt.config.ts 中添加运行时配置 runtimeConfig: {apiKey: "…

Kafka和Zookeeper的基本概念及使用方法

一、什么是Kafka和Zookeeper&#xff1f; Kafka概念&#xff1a; Kafka 是一种分布式流处理平台&#xff0c;最初由 LinkedIn 开发&#xff0c;后成为 Apache 开源项目。它主要用于构建实时数据管道和流应用&#xff0c;具有高吞吐量、低延迟和可扩展性。 Zookeeper概念&#x…

3DUNet-Pytorch-master环境配置(3dunet)

1. 移除虚拟环境 conda remove --name 3dUnet --all 2. 查看虚拟环境 conda env list 2. 创建虚拟环境的命令 conda create --name 3dunet python3.8 &#xff08;之前用的 python3.6 因为重装了系统这个版本不能用了&#xff09; 3. 安装依赖包 pip3 install torch pi…

003 SpringBoot集成Kafka操作

4.SpringBoot集成Kafka 文章目录 4.SpringBoot集成Kafka1.入门示例2.yml完整配置3.关键配置注释说明1. 生产者优化参数2. 消费者可靠性配置3. 监听器高级特性4. 安全认证配置 4.配置验证方法5.不同场景配置模板场景1&#xff1a;高吞吐日志收集场景2&#xff1a;金融级事务消息…

C# tostring 转换成16进制

在 C# 中&#xff0c;将整数或其他数据类型转换为十六进制字符串可以使用 ToString 方法&#xff0c;并指定格式化字符串为 "X" 或 "x"。以下是详细的实现方法和示例&#xff1a; 1. 整数转换为十六进制字符串 使用 ToString 方法并指定格式化字符串为 &q…