← 返回题目列表

观察者模式和发布订阅模式有什么区别?

高频 中等 第 5 / 27 题 更新于 2026/07/28
观察者模式发布订阅事件总线设计模式对比

简化版

观察者模式通常是主题直接维护观察者并通知它们,发布方和订阅方仍通过主题存在一定关联;发布订阅模式通常引入事件通道、消息队列或事件总线,发布方和订阅方不直接知道彼此,解耦更彻底。

详细版

两者都属于事件通知思想,但结构层次不同。

观察者模式:

  • Subject 持有 Observer 列表;
  • Subject 直接调用 Observer;
  • 常用于进程内对象通知;
  • 结构简单,调用关系相对直接。

发布订阅模式:

  • 发布者把消息发到 Broker、Topic 或 EventBus;
  • 订阅者订阅某类主题;
  • 发布者和订阅者不直接关联;
  • 常用于跨模块、跨进程、异步消息场景。

可以理解为:发布订阅是观察者思想在事件中介层上的工程化扩展。比如手写监听器更像观察者模式,Kafka、RabbitMQ、Redis Pub/Sub、事件总线更像发布订阅模式。

完整版教学

一、观察者模式是直接通知

经典观察者模式中,Subject 知道有哪些 Observer。

Subject
  -> Observer A
  -> Observer B
  -> Observer C

Subject 通知时会遍历观察者列表,直接调用观察者方法。

这种结构适合进程内、对象级别的通知。例如 GUI 按钮点击后通知监听器,配置对象变化后通知监听者。

二、发布订阅模式引入中介

发布订阅模式中,发布者通常不直接保存订阅者列表,而是把消息交给一个中介。

Publisher -> Topic/Broker/EventBus -> Subscriber

发布者只知道自己发布了某个主题的消息,订阅者只知道自己订阅了某个主题。双方不直接依赖。

这让系统更适合异步化、跨服务通信和削峰填谷。

三、核心区别是有没有中间层

观察者模式和发布订阅模式最关键的区别是:通知是否通过独立中间层转发。

观察者模式里:

  • 主题通常负责保存观察者;
  • 主题直接调用观察者;
  • 通知关系在代码里比较明确。

发布订阅模式里:

  • 发布者不直接保存订阅者;
  • 消息由事件总线、Broker 或 Topic 管理;
  • 订阅关系更动态,也更隐式。

所以发布订阅的解耦程度更高,但排查链路也更复杂。

四、同步和异步不是唯一判断标准

很多人会说“观察者是同步,发布订阅是异步”,这个说法不够严谨。

观察者模式可以做异步通知,比如主题遍历观察者时把任务丢到线程池。

发布订阅也可以在进程内同步调用,比如某些 EventBus 可以同步分发事件。

因此同步异步不是本质区别。本质区别仍然是发布方和订阅方之间是否通过中介层解耦。

五、工程中如何选择

如果是同一个进程内的轻量事件,观察者模式或 Spring 事件就够了。

如果需要跨服务、可靠投递、失败重试、削峰、消费组、消息堆积能力,就应该考虑消息队列形式的发布订阅。

例如:

  • 用户界面点击按钮:观察者模式;
  • Spring 应用内发布领域事件:进程内事件机制;
  • 订单支付后通知库存、物流、营销系统:消息队列发布订阅更稳。

六、直接引用和中介路由的差异

进程内 Subject 直接遍历 5 个 Observer,需要维护 5 个引用;发布订阅通过 Broker 按 topic 路由,发布者持有 0 个订阅者引用。

observer: Subject -> Observer; pubsub: Publisher -> Broker/topic -> Subscriber

这个推演把模式带来的收益和成本放在同一条调用链上。设计评审时既要确认结果正确,也要确认额外层次没有改变原有契约。

七、边界、代价与验证

检查维度应确认的内容
正确性同步异步不是唯一标准;核心要看发布者是否直接管理订阅关系,还是由中介解耦。
适用边界Broker 能带来跨进程、持久化和异步能力,但也增加运维、序列化、重复投递和一致性成本。
测试证据覆盖正常路径、异常路径、空值或未知类型,并断言调用次数与顺序
运行成本记录额外对象、调用层数、延迟、线程或内存开销,不用模式名称代替测量

模式落地后要用单元测试验证独立职责,用集成测试验证对象装配和真实调用入口。涉及并发、远程或异步时,还要补充竞态、超时、重复执行与资源释放测试。

易错点:同步异步不是唯一标准;核心要看发布者是否直接管理订阅关系,还是由中介解耦。

八、常见误区与追问

  • 误区:只要异步通知就是发布订阅。 本地观察者也可异步执行,发布订阅也可能同步转发,不能用线程模型单独判断。
  • 误区:发布事件天然等于异步和最终一致性。 观察者只定义一对多通知关系;同步还是异步、是否跨进程以及一致性语义都由具体实现决定。
  • 误区:示例代码能运行,就代表模式边界设计正确。 能运行只证明一条路径,仍要检查异常、并发、顺序、生命周期以及新增实现时是否修改稳定代码。
  • 追问:什么时候从观察者升级到消息系统? 需要跨进程、持久化、削峰、重试或独立扩缩容时才值得承担中间件成本。
  • 追问:观察者失败后由谁重试? 模式本身没有答案;同步场景要定义异常传播,异步场景要由执行器、事件总线或消息系统提供重试与死信策略。
  • 追问:怎样验证这套设计没有改变原有语义? 先做基线行为测试,再对新增层验证返回值、异常类型、调用次数和顺序;性能敏感处还要比较改造前后的量化指标。

九、加强记忆

观察者模式和发布订阅模式都在做事件通知,但观察者偏“主题直接通知观察者”,发布订阅偏“通过中间层按主题转发消息”。有中介层、跨进程、异步解耦、可靠投递需求时,更接近发布订阅模式。