核心内容摘要
小明看看
在软件开发中我们经常遇到这样的场景一个动作发生后需要同时触发一系列后续操作。
如果你把这些操作全部写死在一个方法里代码就会变成一团乱麻所谓的“面条代码”牵一发而动全身。
今天我们通过一个生动的直播间送礼案例来聊聊如何用观察者模式优雅地解决这个问题。
场景引入不仅是送礼那么简单假设你正在开发一个直播 App 的核心功能——送礼。
当用户送出一个“火箭”时后台不仅仅是扣钱那么简单通常还需要触发以下一堆子业务粉丝团系统给用户增加粉丝团经验值。
抽奖系统判断这次送礼是否触发了抽奖资格。
PK系统如果主播正在打 PK需要给 PK 条增加分数。
特效系统在公屏上播放炫酷动画。
[问题] 糟糕的实现方式紧耦合如果不使用设计模式你的GiftService代码很可能是这样的Java代码实现public void sendGift(User user, Gift gift) { //
核心业务扣费 walletService.deduct(user, gift.getPrice()); //
杂七杂八的子业务硬编码在这里 fanClubService.addExp(user,
; // 耦合了粉丝团 lotteryService.check(user); // 耦合了抽奖 pkService.addScore(user, gift.getScore()); // 耦合了PK // 如果明天产品经理说要加个“成就系统”你还得来改这行代码 }痛点很明显违反开闭原则每次增加或删除子功能都要修改sendGift核心代码。
维护困难GiftService变得臃肿不堪且依赖了太多它不该关心的服务。
破局之道观察者模式观察者模式 (Observer Pattern)属于行为型设计模式。
通俗定义它定义了一种一对多的依赖关系。
当一个对象主题的状态发生改变时所有依赖于它的对象观察者都会得到通知并自动更新。
映射到直播间场景我们可以利用观察者模式将“送礼”看作是一个信号其他系统只需要监听这个信号即可。
Subject (主题/被观察者)-直播间送礼服务 (GiftService)职责我是大喇叭。
我只负责送礼送完之后喊一声“有人送礼啦”至于谁想知道你们自己来我这里登记注册。
Observer (观察者)-粉丝团、抽奖、PK系统职责我是听众。
我订阅了送礼事件一旦听到喇叭喊我就赶紧干我自己的活。
代码实战解耦的艺术让我们重构一下上面的代码。
第一步定义观察者接口 (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(粉丝团增加经验值
; } } // 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 { //
维护一个观察者列表花名册 private ListGiftObserver observers new ArrayList(); //
注册方法订阅 public void attach(GiftObserver observer) { observers.add(observer); } //
移除方法取消订阅 public void detach(GiftObserver observer) { observers.remove(observer); } //
通知方法广播 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); } }
深度解析优缺点与
注意事项优点为什么我们要这么做极度解耦GiftService甚至不知道PKObserver的存在。
两者只依赖于抽象接口。
扩展性强双十一活动来了需要送礼掉落碎片只需新建一个ActivityObserver并注册进去核心代码一行都不用改。
符合开闭原则对扩展开放对修改关闭。
缺点你需要警惕的坑同步阻塞问题 在 Java 的标准实现中notifyObservers通常是顺序执行的同步。
如果FanClubObserver卡顿了 5 秒后面的PkObserver就得等 5 秒用户的界面也会卡住。
解决方案对于非关键业务如发通知、加经验建议采用异步处理放入线程池或消息队列。
调试困难 由于逻辑是分散的不像面条代码那样一眼能看完调试时可能需要在一个个观察者之间跳跃流程比较隐晦。
进阶Spring 中的观察者模式在实际的 Java 开发特别是 Spring Boot中我们通常不需要自己手动写 Subject 和 Observer 接口Spring 已经为我们封装好了事件发布-监听机制这正是观察者模式的成熟落地。
定义事件继承ApplicationEvent(比如GiftSentEvent)。
发布者 (Subject)使用ApplicationEventPublisher.publishEvent()。
监听者 (Observer)在方法上添加EventListener注解。
这种方式比手动写 List 维护更加优雅且天然支持解耦。
总结观察者模式就像是生活中的订阅报纸。
报社Subject只管印报纸并分发它不知道也不关心是张三还是李四在读报纸。
当你发现系统中有**“牵一发而动全身”、“一对多联动”**的业务场景时请果断使用观察者模式。
它能让你的核心逻辑保持纯净让复杂的业务链路变得井井有条。