文章目录
- 前言
- 一、概念
- 二、核心结构
- [三、Java 代码实现(订单支付场景)](#三、Java 代码实现(订单支付场景))
-
- [1. 抽象观察者](#1. 抽象观察者)
- [2. 具体观察者(多个)](#2. 具体观察者(多个))
- [3. 抽象主题](#3. 抽象主题)
- [4. 具体主题(订单)](#4. 具体主题(订单))
- [5. 客户端测试](#5. 客户端测试)
- [四、JDK 原生观察者(内置实现)](#四、JDK 原生观察者(内置实现))
- 五、优缺点
- 六、应用场景
- [七、观察者模式 VS 外观模式](#七、观察者模式 VS 外观模式)
- 八、总结
前言
在业务开发中,我们经常遇到一个对象状态改变,需要自动通知一批对象 的场景:比如订单支付成功后,通知库存扣减、通知物流发货、通知积分增加、通知消息推送。如果用硬编码耦合,代码会高度依赖、难以扩展、违背开闭原则。观察者模式就是专门解决一对多通知、解耦发布与订阅的经典行为型设计模式。
一、概念
观察者模式(Observer Pattern) 也叫发布-订阅模式(Publish-Subscribe) ,定义了对象之间一对多 的依赖关系:
当一个对象(主题/被观察者)状态发生改变时,所有依赖它的对象(观察者)都会收到自动通知,并自动更新。
简单理解:
- 主题(Subject):发布者,状态一变就通知所有人
- 观察者(Observer):订阅者,收到通知就执行自己逻辑
- 解耦:发布者只管通知,不管谁订阅;订阅者只管接收,不管谁发布
二、核心结构
- Subject(抽象主题)
提供注册、移除、通知观察者的接口。 - ConcreteSubject(具体主题)
维护状态,状态变化时通知所有观察者。 - Observer(抽象观察者)
定义收到通知后的更新接口。 - ConcreteObserver(具体观察者)
实现更新逻辑,处理自己的业务。
三、Java 代码实现(订单支付场景)
场景:订单支付成功 → 同时触发:
- 库存服务扣减库存
- 积分服务增加积分
- 消息服务发送推送
- 物流服务创建物流单
1. 抽象观察者
java
public interface Observer {
void update(String orderNo);
}
2. 具体观察者(多个)
java
// 库存服务
public class StockObserver implements Observer {
@Override
public void update(String orderNo) {
System.out.println("库存服务:订单" + orderNo + "支付成功,扣减库存");
}
}
// 积分服务
public class PointObserver implements Observer {
@Override
public void update(String orderNo) {
System.out.println("积分服务:订单" + orderNo + "支付成功,增加积分");
}
}
// 消息服务
public class MessageObserver implements Observer {
@Override
public void update(String orderNo) {
System.out.println("消息服务:订单" + orderNo + "支付成功,发送推送");
}
}
// 物流服务
public class LogisticsObserver implements Observer {
@Override
public void update(String orderNo) {
System.out.println("物流服务:订单" + orderNo + "支付成功,创建物流单");
}
}
3. 抽象主题
java
public interface Subject {
void addObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers(String orderNo);
}
4. 具体主题(订单)
java
import java.util.ArrayList;
import java.util.List;
public class OrderSubject implements Subject {
private List<Observer> observerList = new ArrayList<>();
@Override
public void addObserver(Observer observer) {
observerList.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observerList.remove(observer);
}
@Override
public void notifyObservers(String orderNo) {
for (Observer observer : observerList) {
observer.update(orderNo);
}
}
// 模拟支付成功
public void paySuccess(String orderNo) {
System.out.println("订单【" + orderNo + "】支付成功!");
System.out.println("========================");
notifyObservers(orderNo);
}
}
5. 客户端测试
java
public class Client {
public static void main(String[] args) {
// 创建主题
OrderSubject orderSubject = new OrderSubject();
// 添加观察者
orderSubject.addObserver(new StockObserver());
orderSubject.addObserver(new PointObserver());
orderSubject.addObserver(new MessageObserver());
orderSubject.addObserver(new LogisticsObserver());
// 支付成功,自动通知
orderSubject.paySuccess("ORDER_20260327_001");
}
}
输出结果:
订单【ORDER_20260327_001】支付成功!
========================
库存服务:订单ORDER_20260327_001支付成功,扣减库存
积分服务:订单ORDER_20260327_001支付成功,增加积分
消息服务:订单ORDER_20260327_001支付成功,发送推送
物流服务:订单ORDER_20260327_001支付成功,创建物流单
四、JDK 原生观察者(内置实现)
Java 已经提供了标准实现:
- Observable(被观察者/主题)
- Observer(观察者)
实际开发中可以直接用,也可以自己实现。
五、优缺点
优点
- 解耦发布者与订阅者
双方只依赖抽象,不依赖具体实现。 - 符合开闭原则
新增观察者无需修改主题代码。 - 支持广播通知
一次状态变更,自动通知全部订阅者。 - 动态管理
可运行时添加/移除观察者。
缺点
- 观察者太多时,通知效率会下降(可异步优化)。
- 循环依赖可能导致死循环。
- 观察者只知道主题变化,不知道变化过程。
六、应用场景
凡是一个动作触发多个后续流程的场景,都用观察者模式:
- 订单支付:扣库存、加积分、发消息、创建物流
- 用户注册:发欢迎短信、初始化账户、开通权益
- 商品上架:推送订阅用户、同步搜索索引
- 配置变更:实时刷新所有服务配置
- GUI 事件:按钮点击、鼠标移动、键盘输入
- 消息队列、事件总线:本质都是观察者模式
经典框架应用:
- Spring Event
- Spring ApplicationListener
- RabbitMQ / RocketMQ 发布订阅
- Guava EventBus
- Java GUI AWT/Swing 事件
七、观察者模式 VS 外观模式
- 观察者 :一对多,事件驱动、自动通知
- 外观 :一对多,统一入口、封装流程
八、总结
- 观察者模式 = 发布-订阅 = 一对多通知
- 核心:解耦、自动通知、易于扩展
- 结构:主题 + 观察者
- 业务中最常用场景:订单、支付、注册、消息、物流、事件
- 是事件驱动、异步化、解耦架构的基础设计模式