千家信息网

Guava和Spring怎么抽象观察者模式

发表于:2026-10-31 作者:千家信息网编辑
千家信息网最后更新 2026年10月31日,本篇内容主要讲解"Guava和Spring怎么抽象观察者模式",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"Guava和Spring怎么抽象观察者模式"吧!
千家信息网最后更新 2026年10月31日Guava和Spring怎么抽象观察者模式

本篇内容主要讲解"Guava和Spring怎么抽象观察者模式",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"Guava和Spring怎么抽象观察者模式"吧!

什么是观察者模式

观察者模式 是一种行为设计模式,允许定义一种订阅通知机制,可以在对象(被观察者)事件发生时通知多个 "观察" 该对象的观察者对象,所以也被称为 发布订阅模式

其实我个人而言,不太喜欢使用文字去定义一种设计模式的语义,因为这样总是难以理解。所以就有了下面生活中的例子,来帮助读者更好的去理解模式的语义。类图如下所示:

在举例说明前,先让我们熟悉下观察者模式中的 角色类型 以及代码示例。观察者模式由以下几部分角色组成,可以参考代码示例去理解,不要被文字描述带偏

  • 主题(被观察者)(Subject):抽象主题角色把所有观察者对象保存在一个容器里,提供添加和移除观察者接口,并且提供出通知所有观察者对象接口(也有作者通过 Observable 描述)

  • 具体主题(具体被观察者)(Concrete Subject):具体主题角色的职责就是实现抽象目标角色的接口语义,在被观察者状态更改时,给容器内所有注册观察者发送状态通知

public interface Subject {     void register(Observer observer);  // 添加观察者     void remove(Observer observer);  // 移除观察者     void notify(String message);  // 通知所有观察者事件 }  public class ConcreteSubject implements Subject {     private static final List observers = new ArrayList();      @Override     public void register(Observer observer) { observers.add(observer); }      @Override     public void remove(Observer observer) { observers.remove(observer); }      @Override     public void notify(String message) { observers.forEach(each -> each.update(message)); } }
  • 抽象观察者(Observer):抽象观察者角色是观察者的行为抽象,它定义了一个修改接口,当被观察者发出事件时通知自己

  • 具体观察者(Concrete Observer):实现抽象观察者定义的更新接口,可以在被观察者发出事件时通知自己

public interface Observer {     void update(String message);  // String 入参只是举例, 真实业务不会限制 }  public class ConcreteObserverOne implements Observer {     @Override     public void update(String message) {         // 执行 message 逻辑         System.out.println("接收到被观察者状态变更-1");     } }  public class ConcreteObserverTwo implements Observer {     @Override     public void update(String message) {         // 执行 message 逻辑         System.out.println("接收到被观察者状态变更-2");     } }

我们跑一下上面的观察者模式示例,如果不出意外的话会将两个观察者执行逻辑中的日志打印输出。如果是平常业务逻辑,抽象观察者定义的入参是具有业务意义的,大家可以类比项目上使用到的 MQ Message 机制

public class Example {     public static void main(String[] args) {         ConcreteSubject subject = new ConcreteSubject();         subject.register(new ConcreteObserverOne());         subject.register(new ConcreteObserverTwo());         subject.notify("被观察者状态改变, 通知所有已注册观察者");     } }

观察者模式结合业务

因为公司业务场景保密,所以下面我们通过【新警察故事】的电影情节,稍微篡改下剧情,模拟出我们的观察者模式应用场景

假设:目前我们有三个警察,分别是龙哥、锋哥、老三,他们受命跟进犯罪嫌疑人阿祖。如果发现犯罪嫌疑人阿祖有动静,龙哥、峰哥负责实施抓捕行动,老三向警察局摇人,流程图如下:

如果说使用常规代码写这套流程,是能够实现需求的,一把梭的逻辑可以实现一切需求。但是,如果说下次行动,龙哥让老三跟着自己实施抓捕,亦或者说龙哥团队扩张,来了老四、老五、老六...

对比观察者模式角色定义,老四、老五、老六都是具体的观察者(Concrete Observer)

如果按照上面的设想,我们通过"一把梭"的方式把代码写出来会有什么问题呢?如下:

  1. 鸿蒙官方战略合作共建--HarmonyOS技术社区

  2. 首当其冲,增加了代码的复杂性。实现类或者说这个方法函数奇大无比,因为随着警员的扩张,代码块会越来越大

  3. 违背了开闭原则,因为会频繁改动不同警员的任务。每个警员的任务不是一成不变的,举个例子来说这次针对疑犯,让峰哥实施的抓捕行动,下次就可能是疏散民众,难道每次的更改都需要改动"一把梭"的代码

第一种我们可以通过,大函数拆小函数 或者 大类拆分为小类 的方式解决代码负责性问题。但是,开闭原则却不能避免掉,因为随着警员(观察者)的增多及减少,势必会面临频繁改动原函数的情况

当我们面对这种 已知会变动,并且可能会 频繁变动不固定 的代码,就要使用抽象思维来进行设计,进而保持代码的简洁、可维护

这里使用 Java SpringBoot 项目结构来书写观察者模式,代码最终推送到 Github 仓库。读者可以先把仓库拉下来,因为其中不止示例代码,还包括 Guava 和 Spring 的观察者模式实现 GitHub 仓库地址

首先,定义观察者模式中的观察者角色,分别为抽象观察者接口以及三个具体观察者实现类。实际业务中,设计模式会和 Spring 框架相结合,所以示例代码中包含 Spring 相关注解及接口

其次,定义抽象被观察者接口以及具体被观察者实现类。同上,被观察者也需要成为 Spring Bean,托管于 IOC 容器管理

到这里,一个完整的观察者模式就完成了。但是,细心的读者会发现这样的观察者模式会有一个小问题,这里先不说明,继续往下看。接下来就需要实际操练一番,注册这些观察者,通过被观察者触发事件来通知观察者

如何实现开闭原则

看了应用的代码之后,函数体过大的问题已经被解决了,我们通过 拆分成为不同的具体的观察者类 来拆分总体逻辑。但是开闭原则问题呢?这就是上面所说的问题所在,我们目前是通过 显示的引入具体观察者模式 来进行添加到被观察者的通知容器中,如果后续添加警察老四、老五... 越来越多的警察时,还是需要改动原有代码,问题应该怎么解决呢

其实非常简单,平常 Web 项目基本都会使用 Spring 框架开发,那自然是要运用其中的特性解决场景问题。我们这里通过 改造具体被观察者实现开闭原则

如果看过之前作者写过的设计模式文章,对 InitializingBean 接口不会感到陌生,我们在 afterPropertiesSet 方法中,通过注入的 IOC 容器获取到所有观察者对象 并添加至被观察者通知容器中。这样的话,触发观察者事件,代码中只需要一行即可完成通知

@PostConstruct public void executor() {     // 被观察者触发事件, 通知所有观察者     subject.notify("阿祖有行动!"); }

后续如果再有新的观察者类添加,只需要创建新的类实现抽象观察者接口即可完成需求。有时候,能够被封装起来的不止是 DateUtil 类型的工具类,一些设计模式也可以被封装,继而更好的服务开发者灵活运用。这里会分别介绍 Guava#EventBus 以及 Spring#事件模型

同步异步的概念

在介绍 EventBus 和 Spring 事件模型之前,有一道绕不过去的弯,那就是同步执行、异步执行的概念,以及在什么样的场景下使用同步、异步模型?

  • 同步执行:所谓同步执行,指的就是在发出一个请求后,在没有获得调用结果之前,调用者就会等待在当前代码。直到获取到调用方法的执行结果,才算是结束。总结一句话就是 由调用者主动等待这个调用的结果,未返回之前不执行别的操作

  • 异步执行:而异步执行恰恰相反,发出调用请求后立即返回,并向下执行代码。异步调用方法一般不会有返回结果,调用之后就可以执行别的操作,一般通过回调函数的方式通知调用者结果

这里给大家举个例子,能够很好的反应同步、异步的概念。比如说你想要给体检医院打电话预约体检,你说出自己想要预约的时间后,对面的小姐姐说:"稍等,我查一下时间是否可以",这个时候如果你 不挂电话,等着小姐姐查完告诉你 之后才挂断电话,那这就是同步。如果她说稍等需要查一下,你告诉她:"我先挂了,查到结果后再打过来",那这就是异步+回调

在我们上面写的示例代码上,毋庸置疑是通过同步的形式执行观察者模式,那是否可以通过异步的方式执行观察者行为?答案当然是可以。我们可以通过在 观察者模式行为执行前创建一个线程,那自然就是异步的。当然,不太建议你这么做,这样可能会牵扯出更多的问题。一起来看下 Guava 和 Spring 是如何封装观察者模式

Guava EventBus 解析

EventBus 是 Google Guava 提供的消息发布-订阅类库,是设计模式中的观察者模式(生产/消费者模型)的经典实现

具体代码已上传 GitHub 代码仓库,EventBus 实现中包含同步、异步两种方式,代码库中由同步方式实现观察者模式

因为 EventBus 并不是文章重点,所以这里只会对其原理进行探讨。首先 EventBus 是一个同步类库,如果需要使用异步的,那就创建时候指定 AsyncEventBus

// 创建同步 EventBus EventBus eventBus = new EventBus();  // 创建异步 AsyncEventBus EventBus eventBus = new AsyncEventBus(Executors.newFixedThreadPool(10));

注意一点,创建 AsyncEventBus 需要指定线程池,其内部并没有默认指定。当然也别像上面代码直接用 Executors 创建,作者是为了图省事,如果从规范而言,还是消停的使用默认线程池构建方法创建 new ThreadPoolExecutor(xxx);

EventBus 同步实现有一个比较有意思的点。观察者操作同步、异步行为时,均使用 Executor 去执行观察者内部代码,那如何保证 Executor 能同步执行呢。Guava 是这么做的:实现 Executor 接口,重写执行方法,调用 run 方法

enum DirectExecutor implements Executor {     INSTANCE;      @Override     public void execute(Runnable command) {         command.run();     } }

大家有兴趣可以去看下 EventBus 源码,不是很难理解,工作使用上还是挺方便的。只不过也有不好的地方,因为 EventBus 属于进程内操作,如果使用异步 AsyncEventBus 执行业务,存在丢失任务的可能

Spring 事件模型

Spring 大拿设计的观察者模式抽象是作者看到的最优雅、最功能的设计,如果想要玩耍观察者模式推荐指数 ??????????

如果想要使用 ApplicationEvent 玩转观察者模式,只需要简单几步。总结:操作简单,功能强大

创建业务相关的 MyEvent,需要继承 ApplicationEvent,重写有参构造函数

定义不同的监听器(观察者)比如 ListenerOne 实现 ApplicationListener接口,重写 onApplicationEvent 方法

通过 ApplicationContext#publishEvent 方法发布具体事件

Spring 事件与 Guava EventBus 一样,代码就不粘贴了,都已经存放到 Github 代码仓库。这里重点介绍下 Spring 事件模型的特点,以及使用事项

Spring 事件同样支持异步编程,需要在具体 Listener 实现类上添加 @Async 注解。支持 Listener 订阅的顺序,比如说有 A、B、C 三个 Listener。可以通过 @Order 注解实现多个观察者顺序消费

作者建议读者朋友一定要跑下 ApplicationEvent 的 Demo,在使用框架的同时也 要合理的运用框架提供的工具轮子,因为被框架封装出的功能,一般而言要比自己写的功能更强大、出现问题的几率更少。同时,切记不要造重复轮子,除非功能点不满足的情况下,可以借鉴原有轮子的基础上开发自己功能

到此,相信大家对"Guava和Spring怎么抽象观察者模式"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

观察 观察者 模式 代码 同步 事件 接口 方法 问题 设计 业务 就是 角色 函数 功能 容器 对象 方式 模型 示例 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 手冲咖啡和咖啡机区别 广东万易互联网科技有限公司惠州分公司 博彦科技互联网金融 广州万易互联网科技有限公司 互联网络科技有限公司 中国 科技 互联网 远信互联网科技 万达互联网科技 长亮科技 互联网金融 互联网高科技股票 安控科技rtu产品工业互联网 受益于互联网科技的高速发展 深圳育鹏互联网科技有限公司招聘 明优互联网科技有限公司 云南省自由互联网科技有限公司 互联网相关科技技术 宁波跨境商互联网科技有限公司 互联网科技创新创业项目 北京瑞云互联网科技有限公司 恒生科技互联网指数十大成分股 互联网加科技 深圳天众互联网科技公司 晋城互联网科技 互联网金融科技名词解释 锡山区互联网智能科技产品供应 富国互联网科技002692 江苏互联网科技小贷 上海万顺科技互联网有限公司招聘 米泉互联网科技专业怎么样 每日互联网科技新闻
0