Java 观察者模式的快速概述
Java 观察者模式是 Java 世界中非常知名的解决方案。它的主要目标是实现某种形式的对象交互。特别是,它设计了交互,以便对象可以通知其他依赖对象其状态更改。下图显示了它是如何工作的。
UML 类图以最简单的形式描述了 Java 观察者模式。
实现Observable 接口的类允许注册观察者,也就是说,实现Observer 接口的类带有Observable 可以调用的方法。Observable 在其状态发生变化时通知观察者,并传递一个表示状态变化事件的参数。在不太基本的形式中,注册和通知观察者的责任可以委托给一个单独的类(图中未显示)。
受 Java 观察者模式启发的特定实现
Java 观察者模式可能展示其全部潜力的一个可能场景可能是一个系统,它具有某种形式的工作流,具有特定的、定义良好的阶段。例如,我们可以想象一个基于 Spring 的旧系统,我们想用新功能扩展它,而保留现有代码不变。
本文提出的解决方案允许在不触及现有代码的情况下注入新功能。它通过利用 Spring 框架的一些特性来做到这一点,例如 Spring AOP、Spring BeanPostProcessor 和自定义注解。为简单起见,我们将目标系统表示为一个具有我们假设在软件生命周期中实现一些重要阶段变化的方法的单个类。
我们想要实现的目标
在描述整个事情之前,让我们从我们想要达到的最终结果开始:
- 我们希望使用简单的自定义注解和 bean 必须实现的接口将常规 Spring bean“转换”为目标系统的观察者。我们希望我们的观察者在达到特定系统状态时触发一些新功能。
- 注释必须有一个或多个参数,代表系统状态的一些标识信息(在我们的解决方案中,为了简单起见,我们将定义一个参数)。
- 该接口必须定义一个方法,该方法旨在在状态更改的上下文中执行,其参数表示已发生的事件,其中包含有效负载以及有关当前系统状态的一些信息,详细信息取决于具体的实现。
- 我们希望我们的观察者在我们的应用程序启动时注册。
我们解决方案的总体架构
我们的观察者模式启发了我们在上一节中针对的解决方案,但略有不同。下面的类图显示了总体思路。
显示受 Java 观察者模式启发的解决方案的类图。
在上图中,显示了两个中心类:
1. ObserverPostProcessor:它是一个Spring bean,它实现了String BeanPostProcessor 接口。Spring 将在启动期间调用 BeanPostProcessor 的方法,让我们处理正在加载到 Spring 上下文中的 bean。在我们的例子中, ObserverPostProcessor 的职责是通过静态 Map 属性在ObserverMap对象中注册观察者。它通过检查一个 bean 是否使用@observe 进行注释 ,在这种情况下,它从注释中获取参数值并将观察者放入 ObserverMap 中,并将该参数值作为键。请注意,与之前解释的一般 Observer 设计相比,我们这里有一点不同:我们使用一个单独的类来存储观察者实例。
2. ObserverAspect:这是一个 Spring AOP 切面,配置为拦截对目标系统方法的调用(在我们的示例中由 SystemComponent 类表示)。在这种拦截的上下文中,它提取传递给 SystemComponent 方法的参数,并使用它来获取相应的观察者。它使用该参数创建Event 类的实例,并调用传递该实例的观察者的 notify 方法。与上一节的观察者模式模式相比,这里我们还有另一个不同之处:它是 ObserverAspect,而不是目标系统(经典模式中的“Observable”)负责向注册的观察者发送事件。
基本互动
下面是一张带有两个序列图的图片,分别显示了应用程序启动和运行阶段的基本交互:
显示与 ObserverPostProcessor 和 ObserverAspect 类相关的基本交互的 UML 序列图。
编码整个设计
现在我们已经展示了解决方案的高级描述,让我们详细描述所提供示例的每段代码,然后是相关的代码片段。
观察者界面
此接口有一个名为notify 的方法,其参数类型为Event。当目标系统进入某个特定阶段时,将调用 notify 方法。它的调用机制基于上一节中描述的Spring AOP技术。
事件类
我们可以将Event 类视为我们想要传递给观察者的系统信息的包装器。它包含一个Object 类型的eventPayload 通用属性,该属性将在 notify 方法的观察者实现中转换为实际的对象类型。
观察者地图类
ObserverMap 类用于存储观察者。它通过静态 Map 属性来实现。