观察者模式(Observer Pattern)是 GoF 经典行为型设计模式 ,也被称为发布-订阅模式(Publish-Subscribe)。核心思想:定义一对多的依赖关系,让一个主题对象状态发生改变时,所有依赖它的观察者对象自动收到通知并更新。
该模式完美实现事件驱动、状态联动、解耦通知,是Spring事件机制、消息队列、GUI事件监听、业务联动更新的底层核心,属于面试和开发高频模式。
核心口诀:主题统一发布,观察者被动订阅,状态一变,全员联动。
一、观察者模式核心概述
1.1 核心定义
建立「主题-观察者」的一对多订阅机制:主题(被观察者)维护一组观察者列表,当自身数据、状态发生变更时,自动遍历所有观察者,主动推送更新通知,观察者接收消息后自主执行更新逻辑,全程无需主动轮询。
1.2 解决的核心痛点
常规业务中,多个业务模块依赖同一个核心数据状态,传统写法存在严重缺陷:
-
硬编码耦合严重:核心业务需要手动调用多个依赖模块的更新方法,新增联动模块需修改核心代码,违背开闭原则
-
代码冗余臃肿:大量重复的状态判断、主动调用逻辑,维护成本极高
-
联动灵活性差:无法动态新增、移除、订阅、取消订阅观察者
-
主动轮询消耗资源:通过定时轮询判断状态变更,效率低、实时性差
1.3 四大核心角色
观察者模式拥有固定的标准四层角色架构,职责划分清晰,所有实现均基于该结构拓展:
-
抽象主题(Subject/Observable):被观察者顶层接口,定义订阅、取消订阅、通知更新的统一规范,负责管理所有观察者集合。
-
具体主题(ConcreteSubject):具体被观察者,持有核心状态数据,状态变更时触发通知机制,主动推送消息给所有订阅的观察者。
-
抽象观察者(Observer):观察者顶层接口,定义统一的更新方法,所有具体观察者遵循该规范。
-
具体观察者(ConcreteObserver):实现抽象观察者接口,接收主题通知,执行自身专属的更新、联动业务逻辑。
1.4 标准结构说明
整体架构分为两层核心体系:主题体系、观察者体系,完全解耦分离,无硬编码依赖。

核心关联关系:
-
实现关系:具体主题实现抽象主题接口,所有具体观察者实现抽象观察者接口,保证行为统一、规范统一。
-
聚合关系:抽象主题聚合持有多个抽象观察者,形成一对多的订阅关系,一个主题可绑定无数观察者。
-
触发关系:主题状态变更后,主动回调观察者更新方法,观察者被动接收通知、执行逻辑。
-
解耦关系:主题无需知晓观察者具体实现,仅依赖顶层接口,新增、删除观察者无需修改主题代码。
完整调用链路:业务触发主题状态变更 → 主题遍历所有已订阅观察者 → 批量推送更新通知 → 各观察者独立执行自身更新逻辑 → 完成全局联动。
1.5 核心设计思想
解耦联动、被动通知、动态订阅。将「状态变更」与「后续联动逻辑」彻底拆分,主题只负责状态管理与消息发布,观察者只负责自身业务更新,遵循单一职责与开闭原则。
二、传统硬编码联动弊端(反例对比)
以「订单状态变更联动」为例,订单完成后需要通知库存、消息、积分模块,传统写法耦合严重:
public class OrderService {
// 订单完成,硬编码联动所有模块
public void finishOrder() {
// 核心订单逻辑
System.out.println("订单已完成");
// 硬编码调用联动模块
StockService.reduceStock();
MessageService.sendNotice();
IntegralService.addIntegral();
}
}
缺陷:新增联动模块必须修改OrderService代码,违背开闭原则;模块高度耦合,无法动态增减联动逻辑,代码拓展性极差。
三、观察者模式标准代码实战
业务场景:订单状态变更为完成后,自动联动库存扣减、用户消息推送、会员积分增加,支持后续动态新增联动模块。
3.1 抽象观察者(统一更新规范)
// 抽象观察者:统一更新接口
public interface Observer {
// 接收主题通知,执行更新逻辑
void update(String message);
}
3.2 具体观察者(各模块独立实现)
// 具体观察者1:库存模块
public class StockObserver implements Observer {
@Override
public void update(String message) {
System.out.println("库存模块接收通知:" + message + ",执行商品库存扣减逻辑");
}
}
// 具体观察者2:消息推送模块
public class MessageObserver implements Observer {
@Override
public void update(String message) {
System.out.println("消息模块接收通知:" + message + ",向用户推送订单完成提醒");
}
}
// 具体观察者3:积分模块
public class IntegralObserver implements Observer {
@Override
public void update(String message) {
System.out.println("积分模块接收通知:" + message + ",为用户新增消费积分");
}
}
3.3 抽象主题(被观察者顶层规范)
import java.util.List;
// 抽象主题(被观察者)
public interface Subject {
// 订阅观察者
void registerObserver(Observer observer);
// 取消订阅
void removeObserver(Observer observer);
// 通知所有观察者更新
void notifyObservers(String message);
}
3.4 具体主题(核心状态主体)
import java.util.ArrayList;
import java.util.List;
// 具体主题:订单主题(被观察者)
public class OrderSubject implements Subject {
// 维护所有订阅的观察者
private final List<Observer> observerList = new ArrayList<>();
// 新增订阅
@Override
public void registerObserver(Observer observer) {
observerList.add(observer);
}
// 取消订阅
@Override
public void removeObserver(Observer observer) {
observerList.remove(observer);
}
// 批量通知所有观察者
@Override
public void notifyObservers(String message) {
for (Observer observer : observerList) {
observer.update(message);
}
}
// 核心业务:订单完成,触发通知
public void finishOrder() {
System.out.println("订单核心逻辑:订单交易完成");
// 状态变更,推送消息给所有观察者
notifyObservers("订单状态更新为【已完成】");
}
}
3.5 客户端测试调用
public class ObserverTest {
public static void main(String[] args) {
// 1.创建核心主题(被观察者)
OrderSubject orderSubject = new OrderSubject();
// 2.注册多个观察者(订阅)
orderSubject.registerObserver(new StockObserver());
orderSubject.registerObserver(new MessageObserver());
orderSubject.registerObserver(new IntegralObserver());
// 3.触发主题状态变更,自动联动所有观察者
orderSubject.finishOrder();
}
}
3.6 拓展优势体现
后续需要新增「日志记录、优惠券返还」等联动模块,无需修改原有任何代码,只需新建对应观察者类并完成订阅即可,完全符合开闭原则。
四、JDK内置观察者实现(原生API)
JDK原生提供了观察者模式内置支持(java.util.Observable主题类、java.util.Observer观察者接口),可快速实现标准监听逻辑,适合快速开发场景。
注意:JDK内置API为老旧实现,不支持多线程、自定义扩展,生产级开发推荐自定义实现观察者模式。
五、优缺点深度分析
5.1 优点
-
彻底解耦:主题与观察者完全解耦,互不依赖具体实现,仅依赖顶层接口
-
完美遵循开闭原则:新增、删除联动观察者无需修改主题核心代码,拓展性极强
-
动态订阅灵活:运行期可动态注册、取消订阅观察者,实时调整联动逻辑
-
一对多自动联动:一次状态变更,批量触发所有关联业务,代码简洁无冗余
-
事件驱动思想:摆脱主动轮询,被动通知响应,执行效率、实时性更高
5.2 缺点
-
可能产生广播风暴:观察者数量过多时,批量通知会产生大量联动逻辑,影响性能
-
通知顺序不可控:默认遍历顺序执行观察者逻辑,无法自定义执行优先级
-
单次消息传递:默认统一推送消息,无法精准定向通知指定观察者
-
循环依赖风险:多主题多观察者嵌套订阅,可能出现循环调用、死循环问题
六、适用场景与生产落地
6.1 核心适用场景
-
一个数据状态变更,需要联动多个模块自动更新的业务场景
-
需要动态新增、移除联动逻辑,频繁拓展订阅关系的场景
-
需要实现事件驱动、消息推送、状态监听的业务场景
-
替代主动轮询,提升系统实时性与执行效率的场景
6.2 经典落地场景
-
Spring事件机制:ApplicationListener 事件监听,基于观察者模式实现容器事件发布订阅
-
消息中间件:MQ发布订阅模式,生产者发布消息、消费者监听消费
-
GUI界面事件:按钮点击、窗口监听等事件回调机制
-
业务联动更新:订单状态、支付状态、库存状态变更后的多模块联动
-
配置中心刷新:Nacos、Apollo配置变更,自动推送刷新客户端配置
七、高频面试核心考点
7.1 观察者模式核心本质
一对多事件订阅、状态联动自动通知、业务完全解耦。核心是实现「发布-订阅」机制,分离状态变更与联动逻辑。
7.2 观察者模式 vs 中介者模式
-
观察者:一对多关系,主题统一发布,观察者被动接收,无中间调度层
-
中介者:多对多解耦,所有对象通过中介者通信,彻底消除对象间相互依赖
7.3 自定义观察者与JDK内置观察者区别
-
JDK内置API简洁易用,但扩展性差、不支持多线程、无法定制化
-
自定义观察者灵活度高,可自定义通知规则、执行顺序、异常处理,适配生产复杂场景
八、面试速记总结
观察者模式是行为型模式,核心为主题(被观察者)+ 观察者的一对多订阅架构。核心价值是实现状态变更的自动联动、业务模块彻底解耦,摆脱硬编码与主动轮询。支持动态订阅、灵活拓展,遵循开闭原则,是事件驱动、消息订阅、Spring事件机制的底层核心,生产中优先使用自定义实现,规避JDK原生API的局限性。
终极口诀:一物变动,万物监听,发布解耦,订阅联动。