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

Spring框架之观察者模式 (Observer Pattern)

观察者模式(Observer Pattern)详解

观察者模式(Observer Pattern)是一种行为型设计模式,用于定义对象间的一种 一对多 的依赖关系,使得当一个对象的状态发生改变时,其相关依赖对象能够自动接收到通知并进行相应的更新。观察者模式广泛应用于事件驱动的系统中,是 GUI 应用程序、事件系统、消息推送等场景中的核心设计模式。

1. 观察者模式的定义

1.1 什么是观察者模式?

观察者模式,也称为 发布-订阅模式(Publish-Subscribe Pattern),其核心思想是 “观察者订阅被观察者”。当被观察者(也称为 主题(Subject))的状态发生变化时,所有已订阅的观察者(Observer)都会收到通知,并根据通知做出相应的反应。

1.2 观察者模式的结构

观察者模式通常包含以下几个角色:

  1. Subject(被观察者/主题)
    • 维护一个观察者列表。
    • 提供注册、注销观察者的方法。
    • 当状态改变时,通知所有观察者。
  2. Observer(观察者)
    • 定义一个更新接口,用于接收通知。
  3. ConcreteSubject(具体被观察者)
    • 继承 Subject,实现具体的通知逻辑。
  4. ConcreteObserver(具体观察者)
    • 继承 Observer,实现具体的响应逻辑。

2. 观察者模式的类图

+-----------------+        +----------------+
|   Subject       |<>----->|   Observer     |
+-----------------+        +----------------+
| + attach()      |        | + update()     |
| + detach()      |        +----------------+
| + notify()      |              ^
+-----------------+              |
       ^                         |
       |                         |
+-----------------+        +--------------------+
| ConcreteSubject |        | ConcreteObserver   |
+-----------------+        +--------------------+
| - state         |        | - observerState    |
| + getState()    |        | + update()         |
| + setState()    |        +--------------------+
+-----------------+

3. 观察者模式的实现

以下是一个简单的观察者模式示例。在该示例中,假设有一个天气站(WeatherStation)作为被观察者,多个显示设备(DisplayDevice)作为观察者,天气站会将温度变化通知给所有已注册的显示设备。

3.1 Java 示例代码
import java.util.ArrayList;
import java.util.List;

// 观察者接口
interface Observer {
    void update(float temperature);
}

// 被观察者接口
interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

// 具体的被观察者:天气站
class WeatherStation implements Subject {
    private List<Observer> observers;
    private float temperature;

    public WeatherStation() {
        this.observers = new ArrayList<>();
    }

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

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(temperature);
        }
    }

    // 设置新的温度并通知观察者
    public void setTemperature(float temperature) {
        this.temperature = temperature;
        notifyObservers();
    }
}

// 具体的观察者:手机显示设备
class PhoneDisplay implements Observer {
    private String name;

    public PhoneDisplay(String name) {
        this.name = name;
    }

    @Override
    public void update(float temperature) {
        System.out.println(name + " 显示温度更新为: " + temperature + "°C");
    }
}

// 具体的观察者:平板显示设备
class TabletDisplay implements Observer {
    @Override
    public void update(float temperature) {
        System.out.println("平板设备显示温度更新为: " + temperature + "°C");
    }
}

// 测试客户端
public class ObserverPatternDemo {
    public static void main(String[] args) {
        // 创建被观察者(天气站)
        WeatherStation weatherStation = new WeatherStation();

        // 创建观察者
        PhoneDisplay phoneDisplay = new PhoneDisplay("手机设备1");
        TabletDisplay tabletDisplay = new TabletDisplay();

        // 注册观察者
        weatherStation.registerObserver(phoneDisplay);
        weatherStation.registerObserver(tabletDisplay);

        // 更新天气并通知观察者
        weatherStation.setTemperature(25.5f);
        weatherStation.setTemperature(30.0f);

        // 移除一个观察者
        weatherStation.removeObserver(phoneDisplay);
        weatherStation.setTemperature(28.5f);
    }
}

输出结果

手机设备1 显示温度更新为: 25.5°C
平板设备显示温度更新为: 25.5°C
手机设备1 显示温度更新为: 30.0°C
平板设备显示温度更新为: 30.0°C
平板设备显示温度更新为: 28.5°C

4. 观察者模式的应用场景

观察者模式广泛应用于各种需要事件通知的场景中:

  1. GUI 事件监听
    • 在图形用户界面中,如按钮点击、文本框输入变化等事件处理机制。
  2. MVC 架构
    • 在 MVC 设计模式中,视图(View)会观察模型(Model)的变化,当模型的数据发生变化时,视图会自动更新。
  3. 推送通知系统
    • 应用程序中的消息推送服务、实时更新、订阅发布系统(如 RSS、社交媒体通知)。
  4. 缓存刷新机制
    • 当缓存数据源发生变化时,通知所有相关缓存进行刷新。
  5. 数据库触发器
    • 在数据库中,当某个表的数据发生变化时,可以触发通知其他表或系统。

5. 观察者模式的优缺点

5.1 优点
  • 降低耦合度:被观察者和观察者之间是松耦合关系。被观察者无需知道观察者的具体实现,符合“依赖倒置原则”。
  • 支持广播通信:一个被观察者可以同时通知多个观察者,扩展性强。
  • 符合开闭原则:可以在不修改被观察者的情况下添加新的观察者,实现系统的灵活扩展。
5.2 缺点
  • 潜在的性能问题:如果有大量的观察者,通知所有观察者可能会带来一定的性能开销。
  • 通知顺序不确定:观察者的通知顺序是不确定的,可能会导致数据不一致的情况。
  • 内存泄漏:如果观察者没有正确注销,可能会导致内存泄漏,尤其是在 Java 等需要手动管理观察者注册和注销的语言中。

6. 观察者模式的扩展

6.1 推模型 vs 拉模型
  • 推模型(Push Model)
    • 被观察者主动将变更数据推送给观察者。适用于数据量小、变化频繁的场景。
  • 拉模型(Pull Model)
    • 被观察者仅通知观察者状态已发生变化,观察者自行拉取所需的数据。适用于数据量大、变化不频繁的场景。
6.2 Java 内置的观察者模式

Java 标准库提供了 java.util.Observable 类和 java.util.Observer 接口来实现观察者模式。

示例

import java.util.Observable;
import java.util.Observer;

class NewsAgency extends Observable {
    private String news;

    public void setNews(String news) {
        this.news = news;
        setChanged(); // 标记状态已改变
        notifyObservers(news);
    }
}

class NewsChannel implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("新闻频道收到新闻更新: " + arg);
    }
}

public class JavaObserverExample {
    public static void main(String[] args) {
        NewsAgency newsAgency = new NewsAgency();
        NewsChannel newsChannel = new NewsChannel();

        newsAgency.addObserver(newsChannel);
        newsAgency.setNews("新冠疫情最新动态!");
    }
}

输出

新闻频道收到新闻更新: 新冠疫情最新动态!
6.3 RxJava 的响应式编程
  • 在响应式编程中,观察者模式的思想被广泛应用。RxJava 通过 ObservableObserver 提供了更加灵活和功能丰富的 API 来处理异步数据流。

7. 总结

观察者模式是一种非常常用的设计模式,在许多场景下都能提升系统的扩展性和灵活性。它不仅降低了对象之间的耦合度,还能实现事件驱动的机制,使得系统能够动态响应外部的变化。

  • 优点:松耦合、易于扩展、支持广播通信。
  • 缺点:可能导致性能开销、内存泄漏风险。
  • 适用场景:事件监听、推送通知、MVC 设计模式、数据缓存机制。


http://www.kler.cn/a/393026.html

相关文章:

  • 【vue2.0入门】vue基本语法
  • 软件工程概论项目(二),node.js的配置,npm的使用与vue的安装
  • 【Pikachu】目录遍历实战
  • python: postgreSQL using psycopg2 or psycopg
  • Vue 项目打包后环境变量丢失问题(清除缓存),区分.env和.env.*文件
  • mac终端使用pytest执行iOS UI自动化测试方法
  • 全球经济风雨飘摇,OJK能带领印尼金融创新走多远?
  • 更改Ubuntu22.04锁屏壁纸
  • Unity 性能优化方案
  • docker overlay磁盘空间过高的处理方案
  • 网络技术-网桥模式
  • LVQ 神经网络的 MATLAB 函数详解
  • 大数据面试题--kafka夺命连环问(前15问)
  • Vue3 -- 项目配置之commitlint【企业级项目配置保姆级教程5】
  • D3的竞品有哪些,D3的优势,D3和echarts的对比
  • 服务器集群不做负载均衡可以吗?
  • 鸿蒙进阶篇-属性动画-animateTo转场动画
  • K8S实现反向代理,负载均衡
  • java实际开发中,navicat连接Linux下的mysql服务
  • 数据结构小项目
  • 数据结构---详解栈
  • 「QT」几何数据类 之 QSize 尺寸类
  • 比ChatGPT更酷的AI工具
  • NVT新能德科技入职测评SHL题库更新:数字推理+演绎推理高分答案、真题解析
  • Pycharm PyQt5 环境搭建创建第一个Hello程序
  • AndroidStudio-滚动视图ScrollView