【设计模式】行为型-观察者模式

文章目录

  • 前言
  • 一、概念
  • 二、核心结构
  • [三、Java 代码实现(订单支付场景)](#三、Java 代码实现(订单支付场景))
    • [1. 抽象观察者](#1. 抽象观察者)
    • [2. 具体观察者(多个)](#2. 具体观察者(多个))
    • [3. 抽象主题](#3. 抽象主题)
    • [4. 具体主题(订单)](#4. 具体主题(订单))
    • [5. 客户端测试](#5. 客户端测试)
  • [四、JDK 原生观察者(内置实现)](#四、JDK 原生观察者(内置实现))
  • 五、优缺点
  • 六、应用场景
  • [七、观察者模式 VS 外观模式](#七、观察者模式 VS 外观模式)
  • 八、总结

前言

  在业务开发中,我们经常遇到一个对象状态改变,需要自动通知一批对象 的场景:比如订单支付成功后,通知库存扣减、通知物流发货、通知积分增加、通知消息推送。如果用硬编码耦合,代码会高度依赖、难以扩展、违背开闭原则。观察者模式就是专门解决一对多通知、解耦发布与订阅的经典行为型设计模式。


一、概念

  观察者模式(Observer Pattern) 也叫发布-订阅模式(Publish-Subscribe) ,定义了对象之间一对多 的依赖关系:
当一个对象(主题/被观察者)状态发生改变时,所有依赖它的对象(观察者)都会收到自动通知,并自动更新。

  简单理解:

  • 主题(Subject):发布者,状态一变就通知所有人
  • 观察者(Observer):订阅者,收到通知就执行自己逻辑
  • 解耦:发布者只管通知,不管谁订阅;订阅者只管接收,不管谁发布

二、核心结构

  1. Subject(抽象主题)
    提供注册、移除、通知观察者的接口。
  2. ConcreteSubject(具体主题)
    维护状态,状态变化时通知所有观察者。
  3. Observer(抽象观察者)
    定义收到通知后的更新接口。
  4. ConcreteObserver(具体观察者)
    实现更新逻辑,处理自己的业务。

三、Java 代码实现(订单支付场景)

场景:订单支付成功 → 同时触发:

  1. 库存服务扣减库存
  2. 积分服务增加积分
  3. 消息服务发送推送
  4. 物流服务创建物流单

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(观察者)

实际开发中可以直接用,也可以自己实现。


五、优缺点

优点

  1. 解耦发布者与订阅者
    双方只依赖抽象,不依赖具体实现。
  2. 符合开闭原则
    新增观察者无需修改主题代码。
  3. 支持广播通知
    一次状态变更,自动通知全部订阅者。
  4. 动态管理
    可运行时添加/移除观察者。

缺点

  1. 观察者太多时,通知效率会下降(可异步优化)。
  2. 循环依赖可能导致死循环。
  3. 观察者只知道主题变化,不知道变化过程。

六、应用场景

凡是一个动作触发多个后续流程的场景,都用观察者模式:

  1. 订单支付:扣库存、加积分、发消息、创建物流
  2. 用户注册:发欢迎短信、初始化账户、开通权益
  3. 商品上架:推送订阅用户、同步搜索索引
  4. 配置变更:实时刷新所有服务配置
  5. GUI 事件:按钮点击、鼠标移动、键盘输入
  6. 消息队列、事件总线:本质都是观察者模式

经典框架应用:

  • Spring Event
  • Spring ApplicationListener
  • RabbitMQ / RocketMQ 发布订阅
  • Guava EventBus
  • Java GUI AWT/Swing 事件

七、观察者模式 VS 外观模式

  • 观察者 :一对多,事件驱动、自动通知
  • 外观 :一对多,统一入口、封装流程

八、总结

  1. 观察者模式 = 发布-订阅 = 一对多通知
  2. 核心:解耦、自动通知、易于扩展
  3. 结构:主题 + 观察者
  4. 业务中最常用场景:订单、支付、注册、消息、物流、事件
  5. 事件驱动、异步化、解耦架构的基础设计模式
相关推荐
极光代码工作室9 分钟前
基于SpringBoot的课程预约系统
java·springboot·web开发·后端开发
Leighteen39 分钟前
`try-finally` 里的 `return`:为什么 `finally` 会悄悄改掉返回值、吞掉异常
java·开发语言
名字还没想好☜1 小时前
Go 的 time.After 在 select 循环里内存泄漏:定时器堆积原理与 timer.Reset 正确姿势
java·数据库·golang·go·goroutine
圆山猫2 小时前
[Virtualization](三):RISC-V H-extension 与 Guest 执行模式
android·java·risc-v
caishenzhibiao2 小时前
期货先行者主图 同花顺期货通指标
java·c语言·c#
史呆芬2 小时前
分布式事务实战:微服务跨服务数据一致性解决方案
java·后端·spring cloud
IT界的老黄牛2 小时前
限流命中后该怎么办:直接丢、阻塞等待、延迟重投三种姿势的取舍
java·rocketmq·redisson·令牌桶·削峰·分布式限流
daad7773 小时前
记录matlab状态机demo
java·网络·matlab
牡丹雅忻14 小时前
AES 加密模式演进:从 ECB、CBC 到 GCM 的 C# 深度实践
java·开发语言·c#
学者猫头鹰4 小时前
Java 8 核心新特性
java