前端进阶之旅前端进阶之旅
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
首页程序员面试题库观察者模式 发布订阅 区别
设计设计模式可维护代码

观察者模式与发布订阅模式在耦合方式上的核心区别是什么?

观察者模式中目标直接保存并调用观察者,二者通过接口和列表产生直接关联;发布订阅多一个中介事件通道,发布者与订阅者互不感知。区别就在于这个中间层是否存在。

前端进阶之旅 · 一题精讲更新于 2026.09.05
设计模式#可维护代码
先看核心答案
理解线索

耦合之根:中介通道是否存在

  1. 直接引用目标持有观察者列表并调用更新
  2. 通道中转发布者和订阅者只与事件总线交互
  3. 依赖方向目标依赖观察者接口,发布订阅双方依赖事件契约

若目标仅依赖抽象接口仍是观察者,但耦合仍强于发布订阅;发布订阅引入额外空间与时间解耦。

核心回答

先记住这个答案

观察者模式的目标对象持有观察者集合,状态变化时遍历调用各观察者的更新方法,所以目标必须知道观察者的存在和接口;发布订阅引入独立事件通道,发布者只把事件投递到通道,订阅者自行注册回调,双方不直接引用,甚至不知道对方是谁。前者耦合更紧,同步调用和调试直观;后者彻底解耦,但需额外管理消息路由和生命周期。

  • 观察者模式目标直接关联观察者
  • 发布订阅通过事件通道解耦
  • 选型取决于模块间是否需跨层松散协作

两种机制的解耦层级差异

观察者模式由目标(Subject)维护一个观察者列表,状态变化时遍历列表调用各观察者的特定方法。为了让调用成立,目标必须知道观察者提供了哪个方法,通常要求观察者实现同一个接口。即使面向接口,目标仍直接引用了观察者对象,注册关系是显式的强引用。

发布订阅把通道提升为独立的事件通道(Event Channel/Bus)。发布者只负责产生事件并投递到通道,不关心谁订阅;订阅者向通道注册处理器,不关心谁发布。双方各自与通道通信,彼此无直接引用,耦合被转移为各自与通道的连接。

实时协作者光标同步的选型

假设开发实时协同编辑器,光标位置需同步给多个成员头像。用观察者模式,编辑器模型需要维护观察者列表,并要求各头像组件实现统一更新接口;新增成员时需在模型中注册该观察者。改用发布订阅后,模型只把光标事件发布到协作消息中心,成员头像模块自行订阅该事件并更新,新增成员只需在自身代码中订阅,无需在模型中注册。

该场景发布订阅明显降低模型与视图耦合,便于动态加入和移除订阅者。但代价是消息失去强类型契约,事件名拼错或数据格式不匹配会导致静默失败,需额外约束和调试。观察者虽然耦合紧,但关系透明,适合模块边界明确、数量固定的子系统内部。

硬套发布订阅反而失效的条件

当事件数量少、订阅关系固定且要求强一致时,硬套发布订阅增加复杂度。例如表单校验部件与错误提示紧密关联,若通过全局事件总线传播,其他模块误订阅会造成干扰,且异步消息可能让界面更新延迟。观察者模式让目标直接更新关联组件,时序和性能更可控。

另一失效点是顺序与异常隔离。观察者模式中一个观察者抛错会中断后续通知;发布订阅的具体实现各异,同步实现同样可能因抛错而中断,异步实现则可能独立执行而顺序不可控。若业务依赖通知顺序,比如先更新数据再刷新视图,发布订阅无法保证,需要额外队列机制,此时在目标中显式维护顺序更清晰。

回答前,多想一步

容易答错的地方

把两者当作同义词
许多资料混用两者,但耦合点明显不同:观察者要求目标知道观察者并直接调用,发布订阅通过通道解耦后双方无感知。等同两者会忽略中介层带来的性能、健壮性代价和额外管理负担。
认为发布订阅总是更好
发布订阅解耦彻底,但损失强类型和调用栈透明度,调试困难且事件容易丢失。在模块内部、调用关系固定情况下,观察者模式更简单可靠。选择取决于是否需要跨模块动态扩展,而非盲目追求低耦合。
试着用自己的话回答

面试官还会怎么问?

在 JavaScript 中 EventEmitter 属于哪种模式?

EventEmitter 是发布订阅的典型实现:emit 方只发事件,on 方注册监听,双方通过实例这个中介通讯,不直接引用。但若它有全局单例,则引入匿名广播,区别于观察者模式里的目标对象。

观察者模式如何缓解直接引用带来的强耦合?

可定义观察者接口或抽象类,让目标只依赖接口,并在通知前做空值校验。但注册关系仍是直接引用,无法彻底脱离中介。若想完全解耦还是得引入事件通道,即升级为发布订阅。

使用发布订阅时如何避免事件丢失和误触发?

可用命名空间和枚举限定事件类型,订阅前校验通道合法性,并在数据里带源标识。还可设计超时重试或事务日志,但任何补偿都增复杂度,必须权衡是否值得。

从一道题,走向一组知识

把知识连起来

可维护代码

JavaScript 中观察者模式忘记取消订阅会造成什么内存问题,如何诊断?

同属「可维护代码」专题,接着看 观察者模式 内存泄漏 取消订阅 在具体场景中的处理方式。

可维护代码

什么信号表明一段对象创建逻辑应该收敛为工厂而不是散落在各处 new?

同属「可维护代码」专题,接着看 工厂模式 何时使用 对象创建 在具体场景中的处理方式。

参考资料

  • JavaScript Guide

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 两种机制的解耦层级差异
  3. 实时协作者光标同步的选型
  4. 硬套发布订阅反而失效的条件
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑