当前位置: 首页 > news >正文

观察者模式实战——从消息订阅看一对多通知

观察者模式实战:从事件总线到Android广播的完整落地

本文从零构建一个事件总线,进而对接 Spring ApplicationEvent、Android BroadcastReceiver,最后展示自研框架中"强制下线"的完整实现。所有代码可直接运行,核心思想可迁移至任何需要发布-订阅的业务系统。

文章目录

  • 观察者模式实战:从事件总线到Android广播的完整落地
    • 一、场景与目标
    • 二、角色定义
    • 三、从零构建事件总线
    • 四、Spring ApplicationEvent 标准实现
    • 五、框架实战——强制下线广播
    • 六、测试用例
    • 七、观察者 vs 责任链
    • 八、亮点总结
    • 九、适用场景
    • 十、扩展方向
    • 结语

一、场景与目标

观察者模式解决的核心问题:一个对象的状态变化,需要通知多个接收方,且双方互不感知

本文目标:从最简版事件总线 → Spring标准实现 → Android系统广播 → 框架实战,逐级展示观察者模式的不同落地形态。


二、角色定义

/** * 观察者模式角色枚举 */publicenumObserverRole{/** 被观察者 / 事件发布方 */SUBJECT("主题"),/** 观察者 / 事件接收方 */OBSERVER("观察者"),/** 事件对象 */EVENT("事件"),/** 事件总线 */EVENT_BUS("事件总线");privatefinalStringdesc;ObserverRole(Stringdesc){this.desc=desc;}publicStringgetDesc(){returndesc;}}
Publisher EventBus Listeners ┌──────────┐ post() ┌──────────┐ 逐个通知 ┌──────────────┐ │ 状态变化 │ ────────→│listeners │──────────→│ A: 发短信 │ │ 发布事件 │ │ [A,B,C] │──────────→│ B: 减库存 │ └──────────┘ └──────────┘ │ C: 写日志 │ └──────────────┘ 一对多通知:Publisher不知道谁在监听,Listeners之间互不感知

三、从零构建事件总线

importjava.util.*;importjava.util.concurrent.CopyOnWriteArrayList;/** * 自定义事件对象 */classLoginEvent{privatefinalStringuserId;privatefinalDateloginTime;publicLoginEvent(StringuserId){this.userId=userId;this.loginTime=newDate();}publicStringgetUserId(){returnuserId;}publicDategetLoginTime(){returnloginTime;}}/** * 监听器接口——观察者契约 */interfaceLoginListener{voidonLogin(LoginEventevent);}/** * 事件总线——发布-订阅核心 */classEventBus{// 使用线程安全的 CopyOnWriteArrayListprivatestaticfinalList<LoginListener>listeners=newCopyOnWriteArrayList<>();publicstaticvoidregister(LoginListenerlistener){Objects.requireNonNull(listener,"监听器不能为空");listeners.add(listener);}publicstaticvoidunregister(LoginListenerlistener){listeners.remove(listener);}publicstaticvoidpost(LoginEventevent){Objects.requireNonNull(event,"事件不能为空");for(LoginListenerlistener:listeners){try{listener.onLogin(event);}catch(Exceptione){System.err.println("监听器处理异常: "+e.getMessage());}}}publicstaticintgetListenerCount(){returnlisteners.size();}}

四、Spring ApplicationEvent 标准实现

importorg.springframework.context.ApplicationEvent;importorg.springframework.context.ApplicationEventPublisher;importorg.springframework.context.event.EventListener;importorg.springframework.stereotype.Component;/** * 自定义 Spring 事件 */publicclassOrderPaidEventextendsApplicationEvent{privatefinalStringorderId;publicOrderPaidEvent(Objectsource,StringorderId){super(source);this.orderId=orderId;}publicStringgetOrderId(){returnorderId;}}/** * 监听器一:发送短信 */@ComponentclassSmsNotificationListener{@EventListenerpublicvoidhandleOrderPaid(OrderPaidEventevent){System.out.println("[SMS] 订单"+event.getOrderId()+"已支付,发送短信通知");}}/** * 监听器二:更新库存 */@ComponentclassInventoryUpdateListener{@EventListenerpublicvoidhandleOrderPaid(OrderPaidEventevent){System.out.println("[库存] 订单"+event.getOrderId()+"支付完成,扣减库存");}}/** * 监听器三:记录审计日志 */@ComponentclassAuditLogListener{@EventListenerpublicvoidhandleOrderPaid(OrderPaidEventevent){System.out.println("[审计] 订单"+event.getOrderId()+"支付记录已写入审计日志");}}/** * 支付服务——事件发布方 */@ComponentclassPaymentService{privatefinalApplicationEventPublisherpublisher;publicPaymentService(ApplicationEventPublisherpublisher){this.publisher=publisher;}publicvoidpay(StringorderId){System.out.println("[支付] 订单"+orderId+"支付成功");// 发布事件——不知道谁在监听publisher.publishEvent(newOrderPaidEvent(this,orderId));}}

五、框架实战——强制下线广播

importandroid.content.BroadcastReceiver;importandroid.content.Context;importandroid.content.Intent;importjava.util.ArrayList;importjava.util.List;/** * 广播接收器——收到"强制下线"指令后清空所有Activity */publicclassForceLogoutReceiverextendsBroadcastReceiver{@OverridepublicvoidonReceive(Contextcontext,Intentintent){// 关闭所有ActivityActivityContainer.finishAll();// 跳转登录页IntentloginIntent=newIntent(context,LoginActivity.class);loginIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);context.startActivity(loginIntent);}}/** * 全局 Activity 容器——观察者模式中的"监听器管理" */classActivityContainer{privatestaticfinalList<BaseActivity>activities=newArrayList<>();publicstaticsynchronizedvoidaddActivity(BaseActivityactivity){activities.add(activity);}publicstaticsynchronizedvoidremoveActivity(BaseActivityactivity){activities.remove(activity);}publicstaticsynchronizedvoidfinishAll(){// 倒序遍历避免ConcurrentModificationfor(inti=activities.size()-1;i>=0;i--){BaseActivityactivity=activities.get(i);if(activity!=null&&!activity.isFinishing()){activity.finish();}}activities.clear();}}/** * 基础Activity——自动注册到全局容器 */classBaseActivity{privatebooleanfinishing=false;protectedvoidonCreate(){ActivityContainer.addActivity(this);}protectedvoidonDestroy(){ActivityContainer.removeActivity(this);}publicbooleanisFinishing(){returnfinishing;}publicvoidfinish(){finishing=true;}}

六、测试用例

importjava.util.concurrent.atomic.AtomicInteger;publicclassObserverTest{publicstaticvoidmain(String[]args){System.out.println("=== 自定义事件总线测试 ===");// 注册监听器AtomicIntegersmsCount=newAtomicInteger(0);AtomicIntegerauditCount=newAtomicInteger(0);EventBus.register(event->{smsCount.incrementAndGet();System.out.println("[SMS] 用户 "+event.getUserId()+" 登录");});EventBus.register(event->{auditCount.incrementAndGet();System.out.println("[审计] 记录登录: "+event.getUserId());});// 发布事件EventBus.post(newLoginEvent("user001"));// 验证System.out.println("\n=== 结果验证 ===");System.out.println("监听器数量: "+EventBus.getListenerCount());System.out.println("短信通知数: "+smsCount.get());// 1System.out.println("审计日志数: "+auditCount.get());// 1// 注销并验证EventBus.unregister(EventBus.listeners.get(0));System.out.println("注销后监听器数量: "+EventBus.getListenerCount());// 1}}

七、观察者 vs 责任链

维度观察者模式责任链模式
通知方式广播,所有观察者都收到链式传递,节点决定是否继续
处理方式各自独立处理按顺序处理
终止条件全部处理完毕任一节点可截断
调用方感知不知道谁在监听不知道链有多长
典型场景消息订阅、事件通知权限校验、过滤器链

八、亮点总结

✅ 三种形态逐级递进:自研总线 → Spring标准 → Android广播
✅ 线程安全的 CopyOnWriteArrayList 实现
✅ 异常隔离——一个监听器失败不影响其他监听器
✅ Activity 容器 + BroadcastReceiver 的完整强制下线方案
✅ 观察者与责任链的对比,清晰区分两种模式
✅ 完整可运行测试代码


九、适用场景

  • 事件驱动的微服务架构
  • UI 组件间通信(MVP/MVVM)
  • 消息推送系统
  • 系统广播与自定义广播
  • 插件系统的事件通知
  • 数据变更的多方同步

十、扩展方向

  1. 异步事件总线——使用线程池处理事件
  2. 事件优先级——监听器排序执行
  3. 事件持久化——未处理事件重启后补偿
  4. 分布式事件总线——跨进程/跨服务
  5. 集成MQ——Kafka/RabbitMQ作为事件传输层

结语

观察者模式是所有事件驱动架构的基石。从15行的事件总线到Spring的ApplicationEvent,从Android系统广播到框架的强制下线——实现方式各不相同,但注册→通知→处理的三步走从未改变。理解了这个三步走,任何发布-订阅系统本质上都是观察者模式。

http://www.jsqmd.com/news/933322/

相关文章:

  • Longest Valid Parentheses(动态规划)
  • OrCAD端口转换补丁实测:一键切换Port与Off-Page Connector,附详细安装避坑指南
  • STM32F030C8T6直接可用的W25Q128 SPI Flash驱动工程(Keil MDK-ARM v5,含.hex和完整CubeMX项目)
  • 2026年亲测AI论文写作软件榜单(安全合规版)
  • Sora 2配音与Premiere Pro/FCPX/Davinci Resolve无缝协同指南,附官方未文档化的Timecode Injection协议
  • 2026年近期想找温州老爹鞋直销厂商?这五家实力供应商值得关注 - 2026年企业资讯
  • LeetCode--Search a 2D Matrix II(分治策略)
  • 从漆包线到发光盆景:手工焊接1206贴片LED的电子艺术实践
  • 基于Arduino与NeoPixel的智能光剑制作:从电路设计到3D打印全流程
  • 如何快速掌握Illustrator脚本:提升设计效率的完整实战指南
  • 新手也能搞定!用ADS 2023一步步仿真LNA的直流偏置与稳定性(附原理图)
  • 2026年5月无溶剂环氧涂料工厂推荐,环氧酚醛/光固化保护套/石墨烯涂料/无溶剂环氧涂料,无溶剂环氧涂料批发厂家怎么选 - 品牌推荐师
  • FortiGate 7.4.2 新机开箱第一步:从接上网线到设置中文界面的保姆级避坑指南
  • Spring Boot 3 + Swagger 3 + Knife4j 4.1.0:从配置到美化,打造团队都爱用的API文档(避坑指南)
  • 如何免费永久保存微信聊天记录:WeChatMsg终极完整使用指南
  • WSL2 Ubuntu 20.04 装完Docker报错?别慌,一个命令切换iptables模式就能搞定
  • Unique Paths II(动态规划)
  • 格式规范否?8款AI论文写作工具梯队榜,毕业答辩稳了!
  • 【Sora 2倒放视频生成黑科技】:全球仅3家实验室验证的时序逆向建模方法首度公开
  • 2026年6月,北京花洒置物平台服务商深度解析:为何恒洁卫浴成为品质之选? - 2026年企业资讯
  • 统计思维实战自测:提升数据决策力,避开常见认知陷阱
  • AI生成图能注册版权吗?(美国版权局2023-2024全部裁定原文深度拆解)
  • 保姆级教程:用Python和Pandas快速上手UJIIndoorLoc室内定位数据集
  • 2026年管道式电磁流量计TOP5选型参考名录:管道式电磁流量计、蒸汽涡街流量计、超声波液位计、一体化温度变送器选择指南 - 优质品牌商家
  • FreeSWITCH新手避坑指南:第一次用fs_cli必须知道的3个关键点和1个危险操作
  • 网络编程的三要素
  • 惊了!输入题目,这几款AI写作辅助软件就能生成图文并茂的毕业论文
  • 用micro:bit与舵机制作交互式纸板机器人:从电容触摸到机械传动
  • OV系列摄像头SCCB总线配置避坑指南:从三线到两线,时序参数怎么调才稳定?
  • 告别VCP!用FTDI D2XX库直接驱动MPSSE引擎(以FT2232H为例,含C++/Qt代码)