news 2026/4/23 13:15:55

设计模式篇2——观察者模式:以直播间送礼系统举例

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
设计模式篇2——观察者模式:以直播间送礼系统举例

在软件开发中,我们经常遇到这样的场景:一个动作发生后,需要同时触发一系列后续操作

如果你把这些操作全部写死在一个方法里,代码就会变成一团乱麻(所谓的“面条代码”),牵一发而动全身。今天,我们通过一个生动的直播间送礼案例,来聊聊如何用观察者模式优雅地解决这个问题。


1. 场景引入:不仅是送礼那么简单

假设你正在开发一个直播 App 的核心功能——送礼。 当用户送出一个“火箭”时,后台不仅仅是扣钱那么简单,通常还需要触发以下一堆子业务:

  1. 粉丝团系统:给用户增加粉丝团经验值。

  2. 抽奖系统:判断这次送礼是否触发了抽奖资格。

  3. PK系统:如果主播正在打 PK,需要给 PK 条增加分数。

  4. 特效系统:在公屏上播放炫酷动画。

[问题] 糟糕的实现方式(紧耦合)

如果不使用设计模式,你的GiftService代码很可能是这样的:

Java代码实现:

public void sendGift(User user, Gift gift) { // 1. 核心业务:扣费 walletService.deduct(user, gift.getPrice()); // 2. 杂七杂八的子业务(硬编码在这里) fanClubService.addExp(user, 10); // 耦合了粉丝团 lotteryService.check(user); // 耦合了抽奖 pkService.addScore(user, gift.getScore()); // 耦合了PK // 如果明天产品经理说要加个“成就系统”,你还得来改这行代码! }

痛点很明显:

  • 违反开闭原则:每次增加或删除子功能,都要修改sendGift核心代码。

  • 维护困难GiftService变得臃肿不堪,且依赖了太多它不该关心的服务。


2. 破局之道:观察者模式

观察者模式 (Observer Pattern)属于行为型设计模式。

通俗定义:它定义了一种一对多的依赖关系。当一个对象(主题)的状态发生改变时,所有依赖于它的对象(观察者)都会得到通知并自动更新。

映射到直播间场景

我们可以利用观察者模式,将“送礼”看作是一个信号,其他系统只需要监听这个信号即可。

  • Subject (主题/被观察者)->直播间送礼服务 (GiftService)

    • 职责:我是大喇叭。我只负责送礼,送完之后喊一声“有人送礼啦”,至于谁想知道,你们自己来我这里登记(注册)。

  • Observer (观察者)->粉丝团、抽奖、PK系统

    • 职责:我是听众。我订阅了送礼事件,一旦听到喇叭喊,我就赶紧干我自己的活。


3. 代码实战:解耦的艺术

让我们重构一下上面的代码。

第一步:定义观察者接口 (Observer)

所有想监听送礼事件的子系统,都必须遵守这个标准。

Java代码实现:

// 观察者接口 public interface GiftObserver { void onGiftSent(User user, Gift gift); }

第二步:实现具体的观察者 (ConcreteObserver)

各个子系统实现接口,编写自己的逻辑。

Java代码实现:

// 粉丝团观察者 public class FanClubObserver implements GiftObserver { @Override public void onGiftSent(User user, Gift gift) { System.out.println("粉丝团:增加经验值 +10"); } } // PK系统观察者 public class PkObserver implements GiftObserver { @Override public void onGiftSent(User user, Gift gift) { System.out.println("PK系统:PK条增加分数 " + gift.getScore()); } }

第三步:改造送礼服务 (Subject)

GiftService不再依赖具体的子系统,而是维护一个观察者列表。

Java代码实现:

public class GiftSubject { // 1. 维护一个观察者列表(花名册) private List<GiftObserver> observers = new ArrayList<>(); // 2. 注册方法(订阅) public void attach(GiftObserver observer) { observers.add(observer); } // 3. 移除方法(取消订阅) public void detach(GiftObserver observer) { observers.remove(observer); } // 4. 通知方法(广播) public void notifyObservers(User user, Gift gift) { for (GiftObserver observer : observers) { observer.onGiftSent(user, gift); } } // 核心业务逻辑 public void sendGift(User user, Gift gift) { // 核心逻辑:扣费 System.out.println("钱包:扣除余额 " + gift.getPrice()); // 关键点:只负责通知,不关心具体是谁在听! notifyObservers(user, gift); } }

4. 深度解析:优缺点与注意事项

优点:为什么我们要这么做?

  1. 极度解耦GiftService甚至不知道PKObserver的存在。两者只依赖于抽象接口。

  2. 扩展性强:双十一活动来了,需要送礼掉落碎片?只需新建一个ActivityObserver并注册进去,核心代码一行都不用改

  3. 符合开闭原则:对扩展开放,对修改关闭。

缺点:你需要警惕的坑

  1. 同步阻塞问题: 在 Java 的标准实现中,notifyObservers通常是顺序执行的(同步)。

    • 如果FanClubObserver卡顿了 5 秒,后面的PkObserver就得等 5 秒,用户的界面也会卡住。

    • 解决方案:对于非关键业务(如发通知、加经验),建议采用异步处理(放入线程池或消息队列)。

  2. 调试困难: 由于逻辑是分散的,不像面条代码那样一眼能看完,调试时可能需要在一个个观察者之间跳跃,流程比较隐晦。


5. 进阶:Spring 中的观察者模式

在实际的 Java 开发(特别是 Spring Boot)中,我们通常不需要自己手动写 Subject 和 Observer 接口,Spring 已经为我们封装好了事件发布-监听机制,这正是观察者模式的成熟落地。

  • 定义事件:继承ApplicationEvent(比如GiftSentEvent)。

  • 发布者 (Subject):使用ApplicationEventPublisher.publishEvent()

  • 监听者 (Observer):在方法上添加@EventListener注解。

这种方式比手动写 List 维护更加优雅,且天然支持解耦。


总结

观察者模式就像是生活中的订阅报纸。报社(Subject)只管印报纸并分发,它不知道也不关心是张三还是李四在读报纸。

当你发现系统中有**“牵一发而动全身”“一对多联动”**的业务场景时,请果断使用观察者模式。它能让你的核心逻辑保持纯净,让复杂的业务链路变得井井有条。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/24 17:20:50

iOS应用上架全面指南:审核流程与要求解析

随着移动互联网的快速发展&#xff0c;iOS平台已成为应用程序分发的重要渠道之一。对于开发者来说&#xff0c;了解iOS上架要求是非常必要的&#xff0c;这有助于确保应用程序顺利通过审核并上架。本文将对iOS上架要求进行详细介绍&#xff0c;帮助开发者更好地了解和遵循相关规…

作者头像 李华
网站建设 2026/4/23 13:14:56

震惊!腾讯企业邮箱在梅州竟有这样的服务商内幕!

深度解析&#xff1a;腾讯企业邮箱在梅州的技术服务商——广东企拓网络科技有限公司的技术突破与实战验证 一、痛点深度剖析&#xff1a;企业邮箱的"最后一公里"困境 在数字化转型浪潮中&#xff0c;企业邮箱作为核心通信工具&#xff0c;却常面临三大技术困境&…

作者头像 李华
网站建设 2026/4/17 22:19:09

阿里双11高并发系统架构设计核心技术全解

据有关数据表明&#xff0c;现在基本工作年限超过5年的Java开发岗以及各大厂招聘岗位&#xff0c;对于高并发这块内容是必定会考察的。这也就意味着&#xff0c;你想要在今年这个大环境下&#xff0c;找到一份薪水高且发展前景好的岗位&#xff0c;不关基础知识还要有良好的编码…

作者头像 李华
网站建设 2026/4/18 5:18:34

1688实时获取商品详情数据-示例

1688作为中国领先的B2B电子商务平台&#xff0c;提供了丰富的API接口&#xff0c;其中商品详情API接口尤为重要。通过该接口&#xff0c;开发者可以获取商品的详细信息&#xff0c;包括标题、价格、规格参数、图片等&#xff0c;为数据分析、库存管理、价格比较等业务场景提供数…

作者头像 李华
网站建设 2026/4/18 7:32:03

疆鸿智能MODBUS TCP转PROFIBUS:网关智构精密组装新脉络

疆鸿智能MODBUS TCP转PROFIBUS&#xff1a;网关智构精密组装新脉络在工业自动化系统的演进中&#xff0c;数据流的无缝贯通是实现智能制造升级的关键。其中&#xff0c;工业通信网关扮演着不可或缺的“协议翻译官”与“数据调度者”角色。本次电子元件精密组装流水线升级项目&a…

作者头像 李华
网站建设 2026/3/28 21:23:12

做自媒体数据复盘工具,导入平台播放量,点赞量,评论量,涨粉数,按日/周统计数据变化,分析高赞作品共性,生成复盘报告。

自媒体数据复盘工具 - 全栈开发实践 1. 实际应用场景描述 本工具专为短视频创作者、公众号作者、播客主播、直播达人等自媒体从业者设计&#xff0c;提供全方位的数据分析和复盘服务。随着自媒体行业的快速发展&#xff0c;内容创作者面临着激烈的市场竞争和用户注意力分散的挑…

作者头像 李华