观察者设计模式(Observer Design Pattern)[论点:概念、组成角色、相关图示、示例代码、框架中的运用、适用场景]

news/2025/3/5 10:53:52/

文章目录

  • 概念
  • 组成角色
  • 相关图示
  • 示例代码
  • 框架中的运用
  • 适用场景

概念

        观察者设计模式(Observer Design Pattern)是一种行为型设计模式,它定义了一种对象间的一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,当主题对象状态发生改变时,通知所有观察者对象,使它们能够自动更新。

组成角色

  1. 主题(Subject):主题是一个抽象类或接口,它定义了添加、删除和通知观察者的方法。
  2. 具体主题(ConcreteSubject):具体主题是主题接口的实现,它包含观察者列表和业务逻辑。当状态发生改变时,具体主题负责通知所有观察者。
  3. 观察者(Observer):观察者是一个抽象类或接口,它定义了一个更新方法,用于接收主题的通知。
  4. 具体观察者(ConcreteObserver):具体观察者是观察者接口的实现,它根据主题的通知来更新自己的状态。

相关图示

在这里插入图片描述

示例代码

        这个代码示例展示了观察者设计模式的基本实现。具体主题ConcreteSubject存储了观察者列表和当前状态,当状态发生改变时,它会通知所有注册的观察者。观察者ConcreteObserverAConcreteObserverB实现了观察者接口Observer,并在更新状态时输出相应的消息。在main方法中,我们创建了一个具体主题和两个具体观察者,将观察者添加到主题中,然后改变主题的状态并观察输出结果。当从主题中移除一个观察者后,再次改变主题状态,可以看到只有剩下的观察者接收到了通知。

import java.util.ArrayList;
import java.util.List;// 主题接口
interface Subject {// 添加观察者void addObserver(Observer observer);// 移除观察者void removeObserver(Observer observer);// 通知所有观察者void notifyObservers();
}// 具体主题
class ConcreteSubject implements Subject {// 存储观察者的列表private List<Observer> observers = new ArrayList<>();// 主题的状态private String state;// 设置状态并通知所有观察者public void setState(String state) {this.state = state;notifyObservers();}// 添加观察者到列表@Overridepublic void addObserver(Observer observer) {observers.add(observer);}// 从列表中移除观察者@Overridepublic void removeObserver(Observer observer) {observers.remove(observer);}// 通知所有观察者状态已改变@Overridepublic void notifyObservers() {for (Observer observer : observers) {observer.update(state);}}
}// 观察者接口
interface Observer {// 更新观察者状态void update(String state);
}// 具体观察者A
class ConcreteObserverA implements Observer {// 当收到主题通知时,更新状态@Overridepublic void update(String state) {System.out.println("ConcreteObserverA received new state: " + state);}
}// 具体观察者B
class ConcreteObserverB implements Observer {// 当收到主题通知时,更新状态@Overridepublic void update(String state) {System.out.println("ConcreteObserverB received new state: " + state);}
}public class ObserverDemo {public static void main(String[] args) {// 创建具体主题ConcreteSubject subject = new ConcreteSubject();// 创建具体观察者A和BConcreteObserverA observerA = new ConcreteObserverA();ConcreteObserverB observerB = new ConcreteObserverB();// 向主题添加观察者A和Bsubject.addObserver(observerA);subject.addObserver(observerB);// 改变主题状态并通知观察者subject.setState("New state 1");subject.setState("New state 2");// 从主题中移除观察者Asubject.removeObserver(observerA);// 再次改变主题状态并通知观察者subject.setState("New state 3");}
}

运行结果
在这里插入图片描述

框架中的运用

在Spring框架中,观察者模式主要应用在事件处理机制中。Spring监听器主要涉及到以下几个构成部分:

  1. ApplicationEvent(事件):
    ApplicationEvent是Spring中所有事件的基类,它继承自java.util.EventObject。自定义事件需要继承ApplicationEvent。当某个特定操作发生时,可以创建一个自定义的ApplicationEvent实例,并将其发布到整个应用程序。
  2. ApplicationListener(监听器):
    ApplicationListener是一个泛型接口,泛型参数为继承自ApplicationEvent的类。监听器负责监听特定类型的事件。实现ApplicationListener接口的类需要实现onApplicationEvent()方法以处理对应的事件。当一个事件被发布时,关注该事件的监听器会收到通知,并执行onApplicationEvent()方法来处理事件。
  3. ApplicationEventPublisher(事件发布器):
    ApplicationEventPublisher是一个接口,负责发布事件。它提供了publishEvent()方法,用于发布事件到整个应用程序。在Spring中,ApplicationContext实现了ApplicationEventPublisher接口,因此事件发布主要由ApplicationContext管理。
  4. ApplicationEventMulticaster(事件多播器):
    ApplicationEventMulticaster是一个接口,负责将事件分发给关联的监听器。SimpleApplicationEventMulticasterApplicationEventMulticaster的一个默认实现。在Spring中,ApplicationEventMulticaster负责管理所有注册的ApplicationListener。当ApplicationEventPublisher发布事件时,ApplicationEventMulticaster会将事件分发给所有关注该事件的监听器。
  • org.springframework.context.ApplicationEvent:

ApplicationEvent是Spring事件模型的基类,它继承了java.util.EventObject。所有自定义事件需要继承ApplicationEvent类。

package org.springframework.context;import java.util.EventObject;public abstract class ApplicationEvent extends EventObject {private static final long serialVersionUID = 7099057708183571937L;private final long timestamp;public ApplicationEvent(Object source) {super(source);this.timestamp = System.currentTimeMillis();}public final long getTimestamp() {return this.timestamp;}
}
  • org.springframework.context.ApplicationListener:

ApplicationListener是一个泛型接口,它的泛型参数是一个继承自ApplicationEvent的类。它类似于观察者模式中的观察者。实现ApplicationListener接口的类需要实现onApplicationEvent()方法以处理事件。

package org.springframework.context;import java.util.EventListener;public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {void onApplicationEvent(E event);
}
  • org.springframework.context.ApplicationEventPublisher:

ApplicationEventPublisher接口负责发布事件。它类似于观察者模式中的主题。实现该接口的类需要实现publishEvent()方法来发布事件。

package org.springframework.context;public interface ApplicationEventPublisher {void publishEvent(ApplicationEvent event);void publishEvent(Object event);
}
  • org.springframework.context.event.SimpleApplicationEventMulticaster

SimpleApplicationEventMulticasterApplicationEventMulticaster接口的一个实现。它负责将事件分发给关联的监听器。其主要方法是multicastEvent(ApplicationEvent),该方法会遍历注册的监听器,并将事件分发给匹配的监听器。

package org.springframework.context.event;public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {// ...@Overridepublic void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {Executor executor = getTaskExecutor();if (executor != null) {executor.execute(() -> invokeListener(listener, event));} else {invokeListener(listener, event);}}}// ...
}
  • org.springframework.context.support.AbstractApplicationContext

AbstractApplicationContext实现了ApplicationEventPublisher接口,因此在Spring中,事件发布主要由ApplicationContext管理。AbstractApplicationContext中的publishEvent(ApplicationEvent)方法会委托给ApplicationEventMulticaster进行事件的发布。

public abstract class AbstractApplicationContext extends DefaultResourceLoaderimplements ConfigurableApplicationContext {// ...@Overridepublic void publishEvent(ApplicationEvent event) {publishEvent(event, null);}@Overridepublic void publishEvent(Object event) {publishEvent(event, null);}protected void publishEvent(Object event, @Nullable ResolvableType eventType) {Assert.notNull(event, "Event must not be null");if (logger.isTraceEnabled()) {logger.trace("Publishing event in " + getDisplayName() + ": " + event);}// Decorate event as an ApplicationEvent if necessaryApplicationEvent applicationEvent;if (event instanceof ApplicationEvent) {applicationEvent = (ApplicationEvent) event;} else {applicationEvent = new PayloadApplicationEvent<>(this, event);if (eventType == null) {eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType();}}// Multicast right now if possible - or lazily once the multicaster is initializedif (this.earlyApplicationEvents != null) {this.earlyApplicationEvents.add(applicationEvent);} else {getApplicationEventMulticaster().multicastEvent(applicationEvent,eventType);}// 发布事件给父级 ApplicationContextif (this.parent != null) {if (this.parent instanceof AbstractApplicationContext) {((AbstractApplicationContext) this.parent).publishEvent(event, eventType);} else {this.parent.publishEvent(event);}}}
}
// ...

总之大概的逻辑是这样

  1. 创建自定义事件CustomEvent,该事件需要继承ApplicationEvent

  2. 创建自定义事件监听器CustomEventListener,该监听器需要实现ApplicationListener<CustomEvent>接口。

  3. 在需要的地方使用ApplicationEventPublisher(通常是ApplicationContext)发布事件。在AbstractApplicationContext中,publishEvent方法会将事件委托给ApplicationEventMulticaster进行发布。

  4. SimpleApplicationEventMulticaster(默认的ApplicationEventMulticaster实现)会将事件分发给关联的监听器。在multicastEvent方法中,它会遍历所有注册的监听器,并将事件分发给匹配的监听器。

  5. 监听器收到事件后,将执行onApplicationEvent()方法处理事件。

        通过上述流程,我们可以看到Spring监听器执行原理是基于观察者设计模式的。当事件发布后,所有关注该事件的监听器都会收到通知并执行相应的操作。这种机制实现了松耦合的事件处理,可以在不同组件之间实现动态交互。

适用场景

  1. 事件处理系统:观察者模式可以用于实现事件驱动的架构,当一个事件发生时,所有关心这个事件的观察者都会收到通知。这在GUI开发、游戏开发等场景中非常常见。
  2. 数据绑定和同步:当多个组件需要共享或同步相同的数据时,可以使用观察者模式。当数据发生变化时,所有依赖于该数据的观察者都会收到通知并自动更新。这在前端开发、实时协同编辑等场景中非常有用。
  3. 消息发布和订阅:观察者模式可以用于实现发布/订阅系统。在这种系统中,发布者负责发布消息,订阅者负责订阅消息。当发布者发布新消息时,所有订阅了该消息的订阅者都会收到通知。这在分布式系统、消息队列、事件总线等场景中非常常见。
  4. 状态监控和报警:在系统监控和报警场景中,观察者模式可以用于实时监控被观察对象的状态。当被观察对象的状态发生异常时,观察者可以根据预定义的规则执行相应的操作,如发送报警邮件、记录日志等。

http://www.ppmy.cn/news/49691.html

相关文章

VS code的常用快捷键

//[TOC](VS code的常用快捷键) 一、编辑器与窗口管理 1&#xff09;新建文件&#xff1a;Ctrl N 2&#xff09;文件之间切换&#xff1a;Ctrl Tab 3&#xff09;打开一个新的VS Code编辑器&#xff1a; Ctrl Shift N 4&#xff09;关闭当前窗口&#xff1a; Ctrl W 5&…

一篇文章教你解决node-sass 4.12.0 安装失败,一劳永逸

已知&#xff1a; 使用mac电脑使用的node版本是v14.20.0 问题&#xff1a;在安装node-sass 4.12.0的时候报错如下 看到这一堆错误&#xff0c;千万不要立马复制粘贴到浏览器去搜&#xff0c;感觉像无头苍蝇乱撞&#xff0c;好歹稍微看一下什么意思。 显而易见是有一个文档40…

Socks5代理:一种安全的网络代理协议

在今天的数字化世界中&#xff0c;网络安全已经成为了一个极为重要的话题。人们越来越关注网络安全问题&#xff0c;因为互联网已经成为了各行各业的基石。但是&#xff0c;随着网络的发展&#xff0c;各种网络攻击也层出不穷&#xff0c;比如黑客攻击、DDoS攻击等等。因此&…

晨控可视化标签在资产管理上的应用及优势

晨控可视化标签在资产管理上的应用及优势 资产是企业功能的核心组成部分&#xff0c;是企业重要的基础设施建设。资产存在的形式各种各样&#xff0c;不仅具有价值高、流动性强、安全管理困难的特点&#xff0c;而且成为资产管理的重要环境之一。通过射频识别技术&#xff0c;…

【模拟IC】版图的基础操作和基础知识总结(1)

今天总结一下在画版图使用的基本操作和遇到的问题及解决方法。# 一、基本操作 &#xff08;1&#xff09;首先是使用layout XL的优势是可以对应原理图的器件&#xff0c;这样方便我们画版图。 &#xff08;2&#xff09;快捷键的操作&#xff1a; F 进行整体版图的居中 K 就是…

docker安装kafka,并集成springboot进行测试

大家好&#xff0c;今天我们开始学习kafka中间件&#xff0c;今天我们改变一下策略&#xff0c;不刷视频学习&#xff0c;改为实践学习&#xff0c;在网上找一些案例功能去做&#xff0c;来达到学习实践的目的。 首先&#xff0c;是安装相关组件。 1. docker安装安装 1.1 yu…

URL 转为QR code(二维码)

推荐一个良心的网站&#xff0c;能够免费地将url、text编码为二维码&#xff0c;而且还能设计logo、颜色等。 https://www.the-qrcode-generator.com/ 如下图&#xff1a; 可以自己定义logo、颜色&#xff1a; 还能查看扫描历史等统计信息&#xff1a; 上述所有功能都是免…

01——计算机系统基础

计算机系统基础知识 计算机系统基础一、计算机系统的基本组成1 计算机硬件系统 二、计算机的类型三、计算机的组成和工作原理1 计算机的组成2 总线的基本概念2.1 总线的定义与分类 3 系统总线3.1 系统总线的概念3.2 常见的系统总线 4 外总线5 中央处理单元&#xff08;CPU&…