什么是观察者模式?应用场景有哪些?
2026年01月27日
一则或许对你有用的小广告
欢迎 加入小哈的星球 ,你将获得: 专属的项目实战(已更新的所有项目都能学习) / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新开坑项目: 《Spring AI 项目实战(问答机器人、RAG 增强检索、联网搜索)》 正在持续爆肝中,基于
Spring AI + Spring Boot3.x + JDK 21..., 点击查看; - 《从零手撸:仿小红书(微服务架构)》 已完结,基于
Spring Cloud Alibaba + Spring Boot3.x + JDK 17..., 点击查看项目介绍; 演示链接: http://116.62.199.48:7070/; - 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/
面试考察点
面试官提出这个问题,通常旨在考察以下几个层面:
- 对设计模式的理解深度:你是否能清晰、准确地描述一种经典设计模式的核心思想与结构,而非仅仅停留在名称上。
- 建模与抽象能力:你是否能将 “一个对象状态变化,其他依赖对象需要得到通知” 这一常见场景,抽象为标准的对象间交互模型。
- 实际应用经验:你是否能在掌握理论的基础上,列举出在真实项目、主流框架或系统中该模式的应用场景,这能反映你的知识迁移能力和工程视野。
- 对松耦合设计的认识:面试官不仅想知道模式是什么,更是想考察你是否理解它在 “解耦” 方面的巨大价值,以及如何通过它来构建更灵活、可维护的系统。
核心答案
观察者模式(Observer Pattern), 也称为发布-订阅模式, 是一种行为型设计模式。它定义了一种一对多的依赖关系, 让多个观察者对象同时监听某一个主题对象。当这个主题对象的状态发生变化时, 会自动通知所有依赖于它的观察者对象, 使它们能够自动更新。
其核心包含两个角色:
- Subject: 主题/被观察者。它维护一个观察者列表, 提供添加、删除观察者的方法, 以及一个通知所有观察者的方法。
- Observer: 观察者。它定义一个更新接口, 用于在接收到主题通知时进行自我更新。
深度解析
原理/机制
观察者模式的核心机制在于回调和依赖管理。主题对象并不需要知道具体是哪些对象在关注它, 它只依赖于一个抽象的观察者接口。当自身状态变更时, 它通过遍历其维护的观察者列表, 调用每个观察者接口中定义的更新方法(如 update()), 从而将变更 “推送” 出去。这个过程实现了 “对象间的动态、松耦合联动”。
代码示例
以下是一个极简的实现, 模拟气象站数据更新时, 多个展示面板(布告板)需要实时刷新的场景。
// 1. 主题接口
interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObservers();
}
// 2. 观察者接口
interface Observer {
void update(float temperature, float humidity, float pressure);
}
// 3. 具体主题:气象数据
class WeatherData implements Subject {
private List<Observer> observers = new ArrayList<>();
private float temperature;
private float humidity;
private float pressure;
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
observers.remove(o);
}
@Override
public void notifyObservers() { // 关键通知方法
for (Observer observer : observers) {
observer.update(temperature, humidity, pressure);
}
}
// 当从传感器获得新数据时,调用此方法
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged(); // 数据变化,触发通知
}
private void measurementsChanged() {
notifyObservers();
}
}
// 4. 具体观察者:当前状况展示布告板
class CurrentConditionsDisplay implements Observer {
private float temperature;
private float humidity;
public CurrentConditionsDisplay(Subject weatherData) {
weatherData.registerObserver(this); // 注册自己
}
@Override
public void update(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
display();
}
public void display() {
System.out.println("当前状况:温度 " + temperature + "°C, 湿度 " + humidity + "%");
}
}
// 5. 使用示例
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
// 可以轻松添加更多观察者,如StatisticsDisplay, ForecastDisplay
// 模拟新数据到达
weatherData.setMeasurements(26.5f, 65.0f, 1013.1f);
weatherData.setMeasurements(27.8f, 70.0f, 1012.5f);
}
}
对比分析与注意事项
- 推模型 vs 拉模型:
- 推模型(如上例):主题将详细的变更数据作为参数传递给观察者。简单直接,但可能传递观察者不需要的信息。
- 拉模型:主题在通知时只传递自身的引用(
this), 观察者根据需要主动从主题中 “拉取” 所需数据。更灵活,但观察者需要知道主题的结构。 - Java 内置的
java.util.Observable(已过时)和java.util.Observer就支持拉模型。
- 最佳实践:
- 抽象主题与观察者:始终依赖接口,这是实现松耦合的关键。
- 注意线程安全:在并发环境下,对观察者列表的增删改查需要同步,或者使用线程安全的集合(如
CopyOnWriteArrayList)。 - 防止内存泄漏:观察者对象在不再需要时,务必从主题中注销(
removeObserver), 否则会因其被主题列表强引用而无法被垃圾回收。
- 常见误区:
- 滥用与过度设计:不是所有状态变化通知都需要用观察者模式。对于简单的回调,直接使用函数式接口(如
Consumer)或监听器接口可能更轻量。 - 混淆事件与状态:观察者模式更侧重于对象状态变化的传播。对于更复杂的事件驱动架构,如Spring ApplicationEvent或消息队列,其思想同源,但实现和功能更强大。
- 滥用与过度设计:不是所有状态变化通知都需要用观察者模式。对于简单的回调,直接使用函数式接口(如
应用场景
观察者模式在真实世界中无处不在:
- GUI 事件监听:Java Swing/AWT、Android 中的各种
OnClickListener都是典型的观察者模式。 - 消息队列/事件总线:这是观察者模式的分布式和异步扩展。生产者发布消息到主题(Topic), 多个消费者订阅该主题并独立处理消息。如 Kafka、RabbitMQ 的核心模型。
- Spring 框架事件机制:
ApplicationContext通过ApplicationEvent和ApplicationListener接口实现了事件发布与监听, 用于解耦业务模块(如订单创建后触发发短信、扣库存等操作)。 - 配置中心动态刷新:如 Apollo、Nacos。当配置在服务端修改后, 所有订阅了该配置的客户端应用会实时收到通知并更新本地配置。
- Reactive 编程:响应式流(如 Project Reactor、RxJava)中的
Flux/Observable就是被观察者, 而subscribe的订阅者就是观察者。
总结
观察者模式通过抽象依赖和回调机制, 实现了主题与观察者之间的松耦合联动, 是应对对象间一对多动态依赖关系的经典解决方案, 在 GUI、事件驱动、消息通信等众多领域有广泛应用。