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

Java设计模式之观察者模式详解

一、观察者模式简介

观察者模式(Observer Pattern)是一种行为型设计模式它定义了对象之间的一对多依赖关系。当一个对象(主题)的状态发生改变时,所有依赖于它的对象(观察者)都会自动收到通知并更新。这种模式又称为发布-订阅模式,广泛应用于事件监听、消息推送、实时数据更新等场景。

1. 核心思想

观察者模式的核心是解耦。主题(Subject)不需要知道观察者(Observer)的具体实现,只需通过接口进行交互。观察者可以动态注册或取消订阅主题的状态变化,从而实现灵活的扩展性和维护性。


二、观察者模式的结构

观察者模式包含以下四个核心角色:

  1. Subject(主题/被观察者)
    定义注册、删除和通知观察者的接口,维护观察者列表。

  2. ConcreteSubject(具体主题)
    实现Subject接口,管理自身状态,并在状态变化时通知所有观察者。

  3. Observer(观察者)
    定义更新接口,接收主题通知。

  4. ConcreteObserver(具体观察者)
    实现Observer接口,根据主题的状态变化执行具体操作。


三、观察者模式的代码实现

1.简单聊天系统示例

⑴.Subject(主题接口)

// 主题接口
interface ChatRoom {void registerUser(User user);void removeUser(User user);void sendMessage(String message);
}

⑵.Observer(观察者接口)

// 观察者接口
interface User {void receiveMessage(String message);
}

⑶.ConcreteSubject(具体主题:聊天室)

// 具体主题:聊天室
class GroupChat implements ChatRoom {private List<User> users = new ArrayList<>();@Overridepublic void registerUser(User user) {users.add(user);System.out.println(user + " 加入了聊天");}@Overridepublic void removeUser(User user) {users.remove(user);System.out.println(user + " 离开了聊天");}@Overridepublic void sendMessage(String message) {System.out.println("发送消息: " + message);for (User user : users) {user.receiveMessage(message);}}
}

⑷.ConcreteObserver(具体观察者:用户)

// 具体观察者:用户
class ChatUser implements User {private String name;public ChatUser(String name) {this.name = name;}@Overridepublic void receiveMessage(String message) {System.out.println(name + " 收到消息: " + message);}@Overridepublic String toString() {return name;}
}

⑸.主类演示

public class SimpleChatSystem {public static void main(String[] args) {//创建聊天室GroupChat chatroom = new GroupChat();//创建用户ChatUser zhangsan = new ChatUser("张三");ChatUser lisi = new ChatUser("李四");ChatUser wangwu = new ChatUser("王五");//注册用户到聊天室chatroom.registerUser(zhangsan);chatroom.registerUser(lisi);chatroom.registerUser(wangwu);//发送信息chatroom.sendMessage("大家好");//移除一个用户chatroom.removeUser(lisi);//再发送一条信息chatroom.sendMessage("lisi已经离开");}
}

运行结果:

⑹.代码解释

①.核心接口和类

  • ChatRoom 接口:定义了主题的三个核心方法:注册用户、移除用户和发送消息。

  • User 接口:定义了观察者的接收消息方法。

  • GroupChat 类:实现了 ChatRoom 接口,维护一个用户列表,并在有新消息时通知所有用户。

②.具体观察者

  • ChatUser 类:实现了 User 接口,当收到消息时会打印消息内容。

③.主类演示

SimpleChatSystem 类:创建了一个 GroupChat 对象和多个 ChatUser 对象,并模拟了消息的发送过程。每次发送消息时,所有注册的用户都会收到通知。

2.天气预报系统

假设我们有一个天气预报系统,当天气数据发生变化时,需要通知所有注册的显示设备。

首先,定义观察者接口:

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

接下来,定义主题接口:

// 主题接口
public interface Subject {void registerObserver(Observer o);void removeObserver(Observer o);void notifyObservers();
}

然后,实现具体主题类:

// 具体主题类
import java.util.ArrayList;
import java.util.List;public class WeatherData implements Subject {private List<Observer> observers;private float temperature;private float humidity;private float pressure;public WeatherData() {observers = new ArrayList<>();}@Overridepublic void registerObserver(Observer o) {observers.add(o);}@Overridepublic void removeObserver(Observer o) {observers.remove(o);}@Overridepublic void notifyObservers() {for (Observer observer : observers) {observer.update(temperature, humidity, pressure);}}public void measurementsChanged() {notifyObservers();}public void setMeasurements(float temperature, float humidity, float pressure) {this.temperature = temperature;this.humidity = humidity;this.pressure = pressure;measurementsChanged();}
}

最后,实现具体观察者类:

// 具体观察者类
public class CurrentConditionsDisplay implements Observer {private float temperature;private float humidity;private Subject weatherData;public CurrentConditionsDisplay(Subject weatherData) {this.weatherData = weatherData;weatherData.registerObserver(this);}@Overridepublic void update(float temperature, float humidity, float pressure) {this.temperature = temperature;this.humidity = humidity;display();}public void display() {System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");}
}

现在,让我们使用这些类来测试我们的天气系统:

// 测试类
public class WeatherStation {public static void main(String[] args) {WeatherData weatherData = new WeatherData();CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);weatherData.setMeasurements(80, 65, 30.4f);weatherData.setMeasurements(82, 70, 29.2f);weatherData.setMeasurements(78, 90, 29.2f);}
}

四、Java 内置的观察者模式支持

Java 提供了内置的观察者模式支持,位于 java.util 包中,包括 Observable 类和 Observer 接口。使用 Java 内置的支持可以简化观察者模式的实现:

import java.util.Observable;
import java.util.Observer;// 使用Java内置的Observable类
public class WeatherData extends Observable {private float temperature;private float humidity;private float pressure;public WeatherData() {}public void measurementsChanged() {setChanged();notifyObservers();}public void setMeasurements(float temperature, float humidity, float pressure) {this.temperature = temperature;this.humidity = humidity;this.pressure = pressure;measurementsChanged();}public float getTemperature() {return temperature;}public float getHumidity() {return humidity;}public float getPressure() {return pressure;}
}// 使用Java内置的Observer接口
public class CurrentConditionsDisplay implements Observer, DisplayElement {Observable observable;private float temperature;private float humidity;public CurrentConditionsDisplay(Observable observable) {this.observable = observable;observable.addObserver(this);}@Overridepublic void update(Observable obs, Object arg) {if (obs instanceof WeatherData) {WeatherData weatherData = (WeatherData)obs;this.temperature = weatherData.getTemperature();this.humidity = weatherData.getHumidity();display();}}@Overridepublic void display() {System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");}
}

五、观察者模式的优缺点

优点:

  • 实现了对象之间的松耦合,主题和观察者可以独立变化和复用。
  • 符合开闭原则,无需修改主题即可增加新的观察者。
  • 支持广播通信,主题可以将通知发送给所有注册的观察者。

缺点:

  • 如果观察者过多,通知所有观察者可能会影响性能。
  • 观察者可能不知道其他观察者的存在,导致调试困难。
  • 如果主题和观察者之间存在循环依赖,可能会导致系统崩溃。

六、观察者模式的应用场景

观察者模式在以下场景中非常有用:

  • 当一个对象的状态变化需要通知其他对象时。
  • 当一个对象需要通知其他对象,而又不希望与这些对象紧密耦合时。
  • 当一个对象的改变需要同时改变其他对象,而不知道具体有多少对象需要改变时。
  • 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面时。

七、总结

观察者模式是一种非常实用的设计模式,它提供了一种对象之间的一对多依赖关系,使得当一个对象的状态发生变化时,所有依赖它的对象都会得到通知并自动更新。Java 提供了内置的支持,使得实现观察者模式变得更加简单。在实际开发中,观察者模式被广泛应用于各种场景,如 GUI 事件处理、消息队列、状态管理等。通过合理使用观察者模式,可以使代码更加灵活、可维护和可扩展。

http://www.lryc.cn/news/2401480.html

相关文章:

  • freeRTOS 消息队列之一个事件添加到消息队列超时怎么处理
  • 十八、【用户认证篇】安全第一步:基于 JWT 的前后端分离认证方案
  • RabbitMQ 开机启动配置教程
  • Authpf(OpenBSD)认证防火墙到ssh连接到SSH端口转发技术栈 与渗透网络安全的关联 (RED Team Technique )
  • 组合与排列
  • 神经网络-Day45
  • 【西门子杯工业嵌入式-1-基本环境与空白模板】
  • Apache Druid
  • 使用深蓝词库软件导入自定义的词库到微软拼音输入法
  • Docker快速部署AnythingLLM全攻略
  • 使用Node.js分片上传大文件到阿里云OSS
  • 高性能分布式消息队列系统(四)
  • C#异步编程:从线程到Task的进化之路
  • [论文阅读] 人工智能+软件工程 | 用大模型优化软件性能
  • 复变函数中的对数函数及其MATLAB演示
  • 【Linux】Linux程序地址基础
  • React 项目初始化与搭建指南
  • 将图形可视化工具的 Python 脚本打包为 Windows 应用程序
  • AWS DocumentDB vs MongoDB:数据库的技术抉择
  • 无人机军用与民用技术对比分析
  • 刷leetcode hot100--矩阵6/1
  • Qt 中实现文本截断(ellipsis)的功能。Qt 提供了此方法来处理过长的文本显示问题,例如在界面中限制文本长度并添加省略号(...)
  • Cisco IOS XE WLC 任意文件上传漏洞复现(CVE-2025-20188)
  • 基于ResNet残差网络优化梯度下降算法实现图像分类
  • 群晖NAS套件历史版本资源
  • Docker轻松搭建Neo4j+APOC环境
  • 定制开发开源AI智能名片S2B2C商城小程序在无界零售中的应用与行业智能升级示范研究
  • CppCon 2015 学习:CLANG/C2 for Windows
  • Spring中@Primary注解的作用与使用
  • Spring Boot + Elasticsearch + HBase 构建海量数据搜索系统