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

文章目录

  • 前言
  • 一、概念
  • 二、核心结构
  • [三、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. 事件驱动、异步化、解耦架构的基础设计模式
相关推荐
庞轩px2 小时前
AQS(AbstractQueuedSynchronizer)源码深度解析:从CLH队列到ReentrantLock实现
java·并发编程·juc·aqs·reentrantlock
江湖中的阿龙2 小时前
深入理解 CAS:Java 无锁并发核心原理、缺陷与应用场景详解
java·开发语言
xianjian09122 小时前
Java进阶-在Ubuntu上部署SpringBoot应用
java·spring boot·ubuntu
拾荒的小海螺2 小时前
JAVA:Spring Boot3 集成 Spring AI 实现 Prompt 提示词工程
java·spring boot·spring
小旭95272 小时前
SpringBoot 整合 MyBatis 与自动配置原理详解
java·spring boot·后端·spring·intellij-idea·mybatis
恼书:-(空寄2 小时前
Seata TCC 生产级(空回滚+悬挂+幂等)+ AT/TCC 混合使用
java·seata·分布式事务
超级无敌大好人2 小时前
程序运行卡住排查
java·spring ai·qdrant
NGC_66112 小时前
深入解析 ConcurrentHashMap 设计思想:高并发下的线程安全哈希表
java·开发语言
无极低码2 小时前
纯Java、无任何第三方依赖、直接可用的 SQLite 工具类
java·jvm·sqlite