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

news/2024/4/26 0:00:25/文章来源:https://blog.csdn.net/asd1358355022/article/details/130346655

文章目录

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

概念

        观察者设计模式(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.luyixian.cn/news_show_102797.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

机器学习 Rider数据集分析和预测

介绍数据集 ride_id&#xff1a;乘车ID rideable_type&#xff1a;乘车类型 started_at&#xff1a;开始日期 ended_at &#xff1a;结束日期 start_station_name&#xff1a;开始站的名字 start_station_id&#xff1a;开始站的ID end_station_name&#xff1a;结束站的名字 …

内网渗透之横向移动rdpwinrmwinrsspnkerberos

0x00 准备 环境&#xff1a;god.org cs上线 win2008web 提权利用ms14-058 抓取hash和明文密码(当获取到其他主机就重复提权和抓取密码) 扫描存活主机&#xff0c;扫描端口 代理转发-转发上线&#xff0c;生成反向连接木马&#xff0c;绑定监听器&#xff0c;上传至web根目录(方…

中小企业真的需要CRM吗?

如果你的企业没有CRM客户关系管理系统&#xff0c;企业主需要问问自己&#xff0c;他们将利用什么来扩展业务。福布斯进行的研究恰当地表明&#xff0c;充分利用CRM系统的企业可以将销售额提高29%。 中小企业定期产生大量客户&#xff0c;这可能会难以管理。这正是CRM系统在有…

《编码——隐藏在计算机软硬件背后的语言》精炼——第12章(二进制加法器)

“I hear and I forget. I see and I remember. I do and I understand”——Confucius 人类计算二进制数的方法 我们先计算本位的结果&#xff0c;称为加法位&#xff1b;再计算是否进位&#xff0c;称为进位位。 搭建二进制加法器 我们用逻辑门来搭建二进制加法器。它的思想…

高可用消息服务消息一致、可靠性、链路稳定性核心关注点

面临的问题 初期业务主要的场景是直播间的群聊消息以及一小部分的单聊消息。由于是教育场景&#xff0c;所以业务在划分聊天室的时候是以班级为单位进行划分的&#xff0c;假设每个聊天室的人数为500人。 问题一&#xff1a;用户的维护 直播场景的群聊与微信等常见的群聊在用…

OpenPCDet复现过程记录

0、前言 OpenPCDet项目之前我就复现过&#xff0c;一个很优秀的项目&#xff0c;这几天又需要用到这个项目&#xff0c;再次复现遇到了不少问题&#xff0c;特此记录复现的流程 1、环境准备 1.1、前置条件 以下是我安装的版本 CUDA 11.3CUDNN 8.2.1 CUDA和CUDNN安装可以参考…

61 openEuler 22.03-LTS 搭建MySQL数据库服务器-管理数据库用户

文章目录 61 openEuler 22.03-LTS 搭建MySQL数据库服务器-管理数据库用户61.1 创建用户示例 61.2 查看用户示例 61.3 修改用户61.3.1 修改用户名61.3.2 修改用户示例61.3.3 修改用户密码61.3.4 修改用户密码示例 61.4 删除用户示例 61.5 用户授权示例 61.6 删除用户权限示例 61…

c实例练习笔记(拓展)

本博文参考题目的地址看右边----》C技能树 我跟你说&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;c语言有bool类型&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;你是不是百度跟你说没有只有c才有&#xff1f; 是有的&#xff01;&#xf…

统计学 实验5

8.14 总体平均值&#xff08;μ&#xff09;&#xff1a;7.0 cm 总体方差&#xff08;σ&#xff09;&#xff1a;0.03 cm 样本平均值&#xff08;x̄&#xff09;&#xff1a;6.97 cm 样本方差&#xff08;s&#xff09;&#xff1a;0.0375 cm 样本大小&#xff08;n&#xff…

数百家数科公司齐聚用友BIP技术大会,共享企业数智化领先实践

4月19日&#xff5e;4月21日&#xff0c;由用友公司主办的“2023用友BIP技术大会“在用友产业园&#xff08;北京&#xff09;盛大召开&#xff0c;用友介绍了更懂企业业务的用友BIP-iuap平台&#xff0c;并发布了全面数智化能力体系&#xff0c;助力企业升级数智化底座&#x…

构建高效数据中台——数据只有被使用起来,才能创造价值

产品经理们时常会碰到这种问题&#xff1a; 我刚上线一个功能&#xff0c;请研发同志们帮我拉个数据出来分析&#xff0c;却被残酷告知需要排期。 我这里急得跺脚&#xff0c;但也只能理解。 数据研发们每天有查不完的数据和写不完的表&#xff0c;业务部门要的数据迟迟拿不到&…

CCBN 2023看点分析:国产8K摄像机国产化替代趋势增强

4月21日&#xff0c;为期3天的CCBN 2023&#xff08;第29届中国国际广播电视信息网络展览会&#xff09;在北京首钢会展中心圆满落幕&#xff0c;CCBN展会是亚洲广播电视设备展览会&#xff0c;也是中国广电行业规模最大、影响力最强的国际性展会之一&#xff0c;更是广电行业内…

同为科技(TOWE)防雷科普篇(二)——雷击灾害急救方法大全

前 言 当雷击发生时&#xff0c;空气中的各种微粒互相碰撞和摩擦便会使该空气介质两面的正负电荷的量持续积累&#xff0c;这时加于该空气介质的电压也会同时增加&#xff0c;当局部电压达到当时条件下空气的击穿电压时&#xff0c;该空气介质的局部便会发生电击穿而持续成为等…

23种设计模式-代理模式

代理模式 在代理模式&#xff08;Proxy Pattern&#xff09;中&#xff0c;一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。 在代理模式中&#xff0c;我们创建具有现有对象的对象&#xff0c;以便向外界提供功能接口。 介绍 意图&#xff1a;为其他对象提供…

发展文旅夜游,活络城市文化生态

城市是一个对外的窗口&#xff0c;其夜间文化生态值得进一步挖掘&#xff0c;发展夜间文旅产业&#xff0c;并活络城市文化生态是重要的城市发展举措。实现这一目标需要保护和利用好城市夜景资源、挖掘城市夜生活文化内涵以及利用特色文化吸引夜游人流量。 第一、要保护和利用好…

ArcGIS、ENVI、InVEST、FRAGSTATS多技术融合提升环境、生态、水文、土地、土壤、农业、大气领域应用

基于ArcGIS、ENVI、InVEST、FRAGSTATS等多技术融合提升环境、生态、水文、土地、土壤、农业、大气等领域的数据分析能力与项目科研水平 点击查看原文 一、空间数据获取与制图 1.1 软件安装与应用讲解 1.2 空间数据介绍 1.3海量空间数据下载 1.4 ArcGIS软件快速入门 1.5 …

20、Theos越狱调试Wallet

前面的总结中使用砸壳重签后的App进行调试,本篇在越狱环境下不重签App进行调试,但是还是需要砸壳获取Headers. 一、Cycript 1.1 在越狱环境中使用Cycript 在越狱环境上,安装Cycript插件.需要先安装adv-cmds插件,因为被Cycript插件所依赖、在Cydia中,安装Cycript 在设备中找到…

苦熬10年,国产操作系统“归零”,新操作系统上新,跟Excel很像

苦熬10余年&#xff0c;国产操作系统自主研发 说到国内自主研发的操作系统&#xff0c;经验最丰富的品牌&#xff0c;当然是麒麟OS. 从诞生到发展&#xff0c;历经10多年的努力&#xff0c;麒麟os逐渐成为了国内自主研发操作系统领域中的一颗耀眼的明珠。麒麟OS不仅推出了许多…

typescript全局安装卸载以及npm相关问题

全局安装 npm install -g typescript 全局安装之后&#xff0c;如果想要卸载要使用 npm uninstall -g typescript 全局安装之后可以在终端使用 tsc xxx 编译ts文件 本地安装&#xff0c;也就是在项目目录下安装 npm install typescript 本地卸载 npm uninstall type…

DHCP 给内网客户端分配ip地址

~ 为 InsideCli 客户端网络分配地址&#xff0c;地址池范围&#xff1a; 192.168.0.110-192.168.0.190/24&#xff1b; ~ 域名解析服务器&#xff1a;按照实际需求配置 DNS 服务器地址选项&#xff1b; ~ 网关&#xff1a;按照实际需求配置网关地址选项&#xff1b; ~ 为…