观察者模式的优缺点是什么?
简化版
观察者模式的优点是发布方和订阅方解耦、方便扩展多个响应动作、符合开闭原则;缺点是调用链变隐式、通知顺序和异常处理复杂、观察者过多可能影响性能,还可能出现循环通知和内存泄漏。
详细版
观察者模式的优点:
- 降低对象间直接依赖;
- 支持一对多通知;
- 新增观察者通常不需要修改发布方;
- 适合事件驱动和扩展点设计;
- 能把主流程和附加动作拆开。
观察者模式的缺点:
- 调用链不直观,排查问题要找事件订阅关系;
- 观察者执行顺序可能影响结果;
- 一个观察者异常可能影响其他观察者;
- 同步通知可能拖慢主流程;
- 注册后不取消可能造成内存泄漏;
- 观察者之间互相触发可能形成循环通知。
面试回答时可以强调:观察者模式适合事件通知和扩展点,但不要把核心强一致流程随意拆成隐式事件链。
完整版教学
一、优点一:降低耦合
观察者模式最大的优点是让发布方不直接依赖所有订阅方。
没有观察者模式时,订单支付成功逻辑可能直接调用短信、积分、日志、营销系统。
使用观察者模式后,订单服务只发布支付成功事件。短信监听器、积分监听器、日志监听器各自响应。
这让主流程更干净,下游扩展也更容易。
二、优点二:方便扩展
新增一个观察者通常不需要修改 Subject。
比如现在支付成功后要新增“推送用户成长值”,只需要新增一个成长值监听器订阅支付成功事件。
这符合开闭原则:对扩展开放,对修改相对关闭。
当然,这个前提是事件本身设计合理。如果事件字段不够,还是可能需要修改事件对象。
三、优点三:适合事件驱动架构
观察者模式是很多事件驱动设计的基础。
它让系统从“直接调用下游”变成“发布事实,让关心这个事实的人响应”。
这种方式特别适合:
- 非核心附加动作;
- 多个模块都关心同一个事件;
- 扩展点机制;
- 领域事件;
- 应用内解耦。
四、缺点一:调用链变隐式
观察者模式让代码依赖变少,但也让调用链不再直观。
你看到:
publishEvent(new OrderPaidEvent(orderId));
很难立刻知道有多少监听器会执行、执行顺序是什么、失败会不会影响主流程。
因此项目里需要通过命名、日志、文档或监控把事件链路暴露出来。
五、缺点二:顺序、异常和性能要设计
如果多个观察者有顺序依赖,观察者模式会变复杂。
例如必须先加积分,再发通知,就不能完全随意地把两者拆成无序观察者。要么显式编排顺序,要么把它们合并到同一个流程里。
异常处理也要明确:一个观察者失败是否影响其他观察者?是否影响发布方?
同步通知还会有性能问题。观察者越多,发布事件耗时越长。
六、缺点三:循环通知和内存泄漏
如果观察者处理事件时又修改 Subject,可能触发新的通知,形成循环。
例如 A 事件触发 B,B 又触发 A,如果没有边界控制,就可能无限循环。
内存泄漏则来自注册后不取消订阅。长生命周期 Subject 持有短生命周期 Observer,会导致 Observer 无法释放。
七、解耦收益与隐式链路成本
一个事件连接 6 个观察者,发布者依赖从 6 个具体类降为 1 个事件契约;但一次发布最多触发 6 条隐藏执行路径。
lower compile-time coupling <-> higher runtime topology complexity
这个推演把模式带来的收益和成本放在同一条调用链上。设计评审时既要确认结果正确,也要确认额外层次没有改变原有契约。
八、边界、代价与验证
| 检查维度 | 应确认的内容 |
|---|---|
| 正确性 | 观察者减少的是静态依赖,不会自动减少系统行为数量和运行成本。 |
| 适用边界 | 扩展频繁、响应彼此独立时收益大;核心强一致流程若事件化,会让失败边界和排障变模糊。 |
| 测试证据 | 覆盖正常路径、异常路径、空值或未知类型,并断言调用次数与顺序 |
| 运行成本 | 记录额外对象、调用层数、延迟、线程或内存开销,不用模式名称代替测量 |
模式落地后要用单元测试验证独立职责,用集成测试验证对象装配和真实调用入口。涉及并发、远程或异步时,还要补充竞态、超时、重复执行与资源释放测试。
易错点:观察者减少的是静态依赖,不会自动减少系统行为数量和运行成本。
九、常见误区与追问
- 误区:观察者越多,发布者性能完全不受影响。 同步通知通常是 O(n) 遍历,异步也会消耗队列、线程和下游资源。
- 误区:发布事件天然等于异步和最终一致性。 观察者只定义一对多通知关系;同步还是异步、是否跨进程以及一致性语义都由具体实现决定。
- 误区:示例代码能运行,就代表模式边界设计正确。 能运行只证明一条路径,仍要检查异常、并发、顺序、生命周期以及新增实现时是否修改稳定代码。
- 追问:如何改善隐式调用链的可观测性? 记录事件 id、类型、发布点、监听器耗时与结果,并为异步链路传递 trace 上下文。
- 追问:观察者失败后由谁重试? 模式本身没有答案;同步场景要定义异常传播,异步场景要由执行器、事件总线或消息系统提供重试与死信策略。
- 追问:怎样验证这套设计没有改变原有语义? 先做基线行为测试,再对新增层验证返回值、异常类型、调用次数和顺序;性能敏感处还要比较改造前后的量化指标。
十、加强记忆
观察者模式的优点是解耦发布方和订阅方、方便一对多扩展;缺点是调用链隐式、顺序和异常处理复杂、同步通知可能拖慢主流程,还要警惕循环通知和内存泄漏。