观察者模式

一、Java观察者模式

Java观察者模式是一种设计模式,用于实现对象之间的一对多依赖关系。在观察者模式中,当一个对象的状态发生变化时,它的所有依赖对象(观察者)都会自动收到通知并进行相应的更新。

观察者模式由以下几个核心组件组成:

  1. 主题(Subject):也称为被观察者或可观察对象,它维护一组观察者对象,并提供方法用于添加、删除和通知观察者。
  2. 观察者(Observer):也称为订阅者或监听器,它定义了接收和处理主题通知的方法。
  3. 具体主题(ConcreteSubject):实现主题接口,维护观察者列表,并在状态发生变化时通知观察者。
  4. 具体观察者(ConcreteObserver):实现观察者接口,定义了接收和处理主题通知的具体逻辑。

观察者模式的工作流程如下:

  1. 观察者通过订阅主题来注册自己,使得主题知道它们的存在。
  2. 当主题的状态发生变化时,它会通知所有注册的观察者。
  3. 观察者收到通知后,根据需要进行相应的更新操作。

观察者模式的优点包括解耦主题和观察者,使得它们可以独立变化;支持动态添加和删除观察者;实现了对象之间的松耦合,提高了系统的灵活性和可扩展性。

  • 场景1:用图来理解:

  • 场景2:多模块开发,解耦情况下,可以模块之间传递参数。

二、Spring实现的观察者模式

1、设计理念

在Spring Boot中,实现观察者模式的设计理念是基于事件驱动的编程模型。Spring Boot提供了一种简单而强大的事件机制,可以方便地实现观察者模式。

以下是Spring Boot实现观察者模式的设计理念:

  1. 事件(Event):事件是触发的动作或状态变化,可以是任何Java对象。在Spring Boot中,事件通常是继承自ApplicationEvent类的对象。

  2. 事件发布者(Event Publisher):事件发布者负责发布事件。在Spring Boot中,可以使用ApplicationEventPublisher接口来发布事件。通常,事件发布者是一个Spring Bean,通过依赖注入ApplicationEventPublisher来发布事件。

  3. 事件监听者(Event Listener):事件监听者是观察者,负责接收和处理事件。在Spring Boot中,可以使用@EventListener注解标记方法,使其成为事件监听者。当事件发布者发布事件时,被标记的方法会自动被调用。

  4. 事件处理逻辑:事件监听者方法中定义了事件的处理逻辑。可以根据具体需求,在事件监听者方法中编写相应的业务逻辑。

通过使用Spring Boot的事件机制,可以实现松耦合的观察者模式。事件发布者和事件监听者之间没有直接的依赖关系,它们通过事件进行通信。这样,可以方便地添加、删除和修改事件监听者,而不需要修改事件发布者的代码。

观察者模式的设计理念在Spring Boot中体现了面向对象编程的原则,如单一职责、开闭原则和依赖倒置原则。它提供了一种灵活、可扩展和可维护的方式来实现事件驱动的编程模型。

2、继承ApplicationEvent和不继承的区别

  • 发送的参数可以是普通JavaBean(String、integer、自定义类)、也可以是继承了ApplicationEvent的JavaBean
如果MyEvent继承ApplicationEvent,则可以使用Spring框架提供的事件传递机制。这意味着可以通过ApplicationEventPublisher发布事件,并且可以使用@EventListener注解标记观察者方法来接收事件。这种方式更符合Spring框架的设计理念,可以方便地实现观察者模式。

如果MyEvent不继承ApplicationEvent,则无法使用Spring框架提供的事件传递机制。需要自己实现事件的传递和观察者模式的逻辑。这种方式更适用于非Spring环境下的观察者模式实现。

继承ApplicationEvent的好处是可以利用Spring框架提供的事件传递机制,简化了观察者模式的实现。同时,还可以利用Spring框架提供的其他特性,如事务管理、AOP等。

不继承ApplicationEvent的好处是更加灵活,可以根据具体需求自由定义事件的结构和传递方式。但需要自己实现事件的传递和观察者模式的逻辑。

综上所述,如果在Spring框架中使用观察者模式,建议继承ApplicationEvent,以便利用Spring框架提供的事件传递机制和其他特性。

3、默认是广播模式

Spring框架中的观察者模式默认是广播模式。

在Spring框架中,当一个事件被发布时,所有注册的观察者都会接收到该事件。这意味着,一个事件可以被多个观察者同时接收和处理,实现了广播的效果。

这种广播模式的实现是通过ApplicationEventMulticaster接口和其默认实现类SimpleApplicationEventMulticaster来完成的。SimpleApplicationEventMulticaster会将事件广播给所有注册的观察者。

当然,如果需要更加细粒度地控制事件的传递方式,也可以自定义ApplicationEventMulticaster的实现类,实现自己的事件传递逻辑。

总结起来,Spring框架中的观察者模式默认是广播模式,一个事件会被所有注册的观察者接收和处理。这种广播模式的实现是通过ApplicationEventMulticaster接口和SimpleApplicationEventMulticaster类来完成的。

三、Spring实现

  • 注意:监听者是异步执行的

1、广播模式(默认)——不推荐

  • 事件 —— 这里先不用,也可以用
  • 这里发送普通的JavaBean的参数,不发送“事件”

1.1、事件(Event)(无)

1.2、事件发布者(Event Publisher)

  • 注入ApplicationEventPublisher来实现
package com.cc.jsl.service.impl;

import com.cc.jsl.service.ILoginService;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service; import javax.annotation.Resource; /**
* <p>事件发布者(Event Publisher)</p>
*
* @author CC
* @since 2023/10/10
*/
@Service
public class LoginServiceImpl implements ILoginService { @Resource
private ApplicationEventPublisher eventPublisher; @Override
public void login(){
//登陆逻辑... //发送
// 1、可以直接发送JavaBean的参数:如String、自定义类
eventPublisher.publishEvent("字符串参数!");
// eventPublisher.publishEvent(new UserCs("cs" , 18));
// eventPublisher.publishEvent(34);
// 2、发送事件参数(继承了ApplicationEvent的类) } }

1.3、事件监听者(Event Listener)

  • 使用@Async、@EventListener实现
  • 可以是很多个,也可以在不同类中
package com.cc.jsl.listener;

import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component; /**
* <p>事件监听者(Event Listener)</p>
*
* @author CC
* @since 2023/10/10
*/
@Component
public class ReceiveListener { /**
* 打电话 - 接收普通JavaBean参数
*/
@Async
@EventListener
public void sendCall(String msg) {
//发送邮件逻辑
System.out.println("打电话!-普通-> " + msg);
} /**
* 发送邮件 - 接收字符串参数
*/
@Async
@EventListener
public void sendEmail(String msg) {
//发送邮件逻辑
System.out.println("发送邮件!-普通-> " + msg);
}
}

2、单个发送(推荐)

  • 每个发送都自定义一个唯一的类,并且继承ApplicationEvent

2.1、事件(Event)

  • 继承ApplicationEvent
  • 继承ApplicationEvent的好处是可以利用Spring框架提供的事件传递机制,简化了观察者模式的实现。同时,还可以利用Spring框架提供的其他特性,如事务管理、AOP等。
package com.cc.jsl.event;

import lombok.Getter;
import lombok.Setter;
import org.springframework.context.ApplicationEvent; /**
* <p>发邮件专属的唯一事件</p>
* <p>需要实现set方法</p>
*
* @author CC
* @since 2023/10/10
*/
@Getter
@Setter
public class EmailEvent extends ApplicationEvent { /**
* 参数1
*/
private String name; /**
* 参数2
*/
private Integer age; public EmailEvent(Object source, String name, Integer age) {
super(source);
this.name = name;
this.age = age;
}
}

2.2、事件发布者(Event Publisher)

package com.cc.jsl.service.impl;

import com.cc.jsl.event.EmailEvent;
import com.cc.jsl.service.ILoginService;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service; import javax.annotation.Resource; /**
* <p>事件发布者(Event Publisher)</p>
*
* @author CC
* @since 2023/10/10
*/
@Service
public class LoginServiceImpl implements ILoginService { @Resource
private ApplicationEventPublisher eventPublisher; @Override
public void login(){
//登陆逻辑... //事件发布
// 1、可以直接发送JavaBean的参数:如String、自定义类
// eventPublisher.publishEvent("字符串参数!");
// eventPublisher.publishEvent(new UserCs("cs" , 18));
// eventPublisher.publishEvent(34); // 2、发送事件参数(继承了ApplicationEvent的类)
EmailEvent emailEvent = new EmailEvent(this, "cc", 18);
eventPublisher.publishEvent(emailEvent);
}
}

2.3、事件监听者(Event Listener)

package com.cc.jsl.listener;

import com.cc.jsl.event.EmailEvent;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component; /**
* <p>事件监听者(Event Listener)</p>
*
* @author CC
* @since 2023/10/10
*/
@Component
public class ReceiveListener { /**
* 打电话 - 接收普通JavaBean参数
*/
@Async
@EventListener
public void sendCall(String msg) {
//发送邮件逻辑
System.out.println("打电话!-普通-> " + msg);
} /**
* 发送邮件 - 接收字符串参数
*/
@Async
@EventListener
public void sendEmail(String msg) {
//发送邮件逻辑
System.out.println("发送邮件!-普通-> " + msg);
} /**
* 发送邮件 - 接收唯一事件
*/
@Async
@EventListener(EmailEvent.class)
public void sendEmail(EmailEvent emailEvent) {
//发送邮件逻辑
System.out.println("发送邮件!-事件-> " + emailEvent);
}
}
  • 发送邮件!-事件-> 除了这个以外的所有监听者都不会监听到消息
  • 经过测试,不使用事件,直接使用自定义类,只有监听了这个类的接受者才能接收到,所以相当于实现了一对一。
  • 自定义事件的好处:可以利用Spring框架提供的事件传递机制,简化了观察者模式的实现。同时,还可以利用Spring框架提供的其他特性,如事务管理、AOP等。
  • 接收到的消息:

四、总结

参考:https://blog.csdn.net/weixin_43745998/article/details/127301003

Java设计模式-观察者模式-SpringBoot实现的更多相关文章

  1. java设计模式--观察者模式(Observer)

    java设计模式--观察者模式(Observer) java设计模式--观察者模式(Observer) 观察者模式的定义: 定义对象间的一种一对多的依赖关系.当一个对象的状态发生改变时,所有依赖于它的 ...

  2. 【设计模式】Java设计模式 - 观察者模式

    [设计模式]Java设计模式 - 观察者模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 @一个有梦有戏的人 @怒放吧德德 分享学习心得,欢迎指正,大家一起学习成长 ...

  3. JAVA 设计模式 观察者模式

    用途 观察者模式 (Observer) 观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象. 这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己. 观 ...

  4. Java设计模式--观察者模式到监听器

    观察者模式是对象的行为模式.又叫做发布-订阅模式.模型-视图模式.源-监听器模式. 抽象主题角色:主题角色将所有对观察者对象的引用到保存在一个集合里,每个主题都可以拥有任意数量的观察者.抽象主题提供一 ...

  5. Java设计模式の观察者模式(推拉模型)

    目录: 一.观察者定义 二.观察者模式的结构(推模式实现) 三.推模型和拉模型(拉模式实现) 四.JAVA提供的对观察者模式的支持 五.使用JAVA对观察者模式的支持(自带推模式实现实例) 一.观察者 ...

  6. Java设计模式 - 观察者模式

    定义 观察者模式属于对象行为型模式. 在对象之间定义一对多的依赖,这样一来当一个对象改变状态,依赖它的对象都会收到通知并自动更新. 优点 1.  主题和观察者之间抽象耦合.无论什么对象主要实现了特定的 ...

  7. 我的Java设计模式-观察者模式

    相信大家都有看过<喜洋洋与灰太狼>,说的是灰太狼和羊族的"斗争",而每次的结果都是灰太狼一飞冲天,伴随着一句"我还会回来的......".为灰太狼感 ...

  8. java设计模式-观察者模式学习

    最近学习了设计模式中的观察者模式,在这里记录下学习成果. 观察者模式,个人理解:就是一个一对多模型,一个主体做了事情,其余多个主体都可以观察到.只不过这个主体可以决定谁去观察他,以及做什么事情可以给别 ...

  9. Java设计模式——观察者模式(事件监听)

    最近在看Tomcat和Spring的源码,在启动的时候注册了各种Listener,事件触发的时候就执行,这里就用到了设计模式中的观察者模式. 引-GUI中的事件监听 想想以前在学Java的GUI编程的 ...

  10. Java设计模式 —— 观察者模式

    16 观察者模式 16.1 观察者模式概述 Observer Pattern: 定义对象之间的依赖关系(一对多),当一个对象的状态发生改变时,其关联的依赖对象均收到通知并自动更新. 观察者模式又称:发 ...

随机推荐

  1. golang gc的内部优化

    今天讲一个常见的gc compiler(也就是官方版本的go编译器和runtime)在垃圾回收的扫描标记阶段做的优化. 我对这个优化的描述印象最深的是在bigcache的注释里,大致内容是如果map的 ...

  2. 如何用LOTO示波器实测LC串联谐振?

    一个电感和一个电容串联,在某个特定的频率,就会发生谐振,这个频率就是谐振频率.串联谐振电路有如下特点: 谐振时整个电路阻抗呈电阻性,阻抗最小,电流达到最大: 谐振时电感和电容两端的电压达到最大. 上图 ...

  3. 从0开始设计_基于STM32F1的RC522读写卡

    从0开始设计_基于STM32F1的RC522读写卡 1.介绍看网上很多RC522的教程都是基于读卡ID的,这个对于很多应用来说其实没有什么用,最近刚好有个项目需要读写卡,而RC522又是非常常用的且不 ...

  4. ChatGPT 指令大全

    1.写报告 报告开头 我现在正在 报告的情境与目的 .我的简报主题是 主题 ,请提供 数字 种开头方式,要简单到 目标族群 能听懂,同时要足够能吸引人,让他们愿意专心听下去. 我现在正在修台大的简报课 ...

  5. 降低FTP服务器速度的解决方案(Filezilla等)

    我最近发现,尽管有70Mbps(8.75MB / s)的互联网连接和1Gbps(125MB / s)的专用服务器可以从中下载,但我似乎只能从FTP服务器上以大约16.8Mbps(2.1MB / s)的 ...

  6. archlinux xfce 设置窗口背景颜色,QT背景颜色

    1.使用xfce主题 2.有QT背景不覆盖,使用配置 sudo pacman -S qt5-ct 3.在/etc/environment添加环境变量 QT_QPA_PLATFORMTHEME=qt5c ...

  7. 稀疏镜像在OpenHarmony上的应用

    一.稀疏镜像升级背景 常用系统镜像格式为原始镜像,即RAW格式.镜像体积比较大,在烧录固件或者升级固件时比较耗时,而且在移动设备升级过程时比较耗费流量.为此,将原始镜像用稀疏描述,可以大大地缩减镜像体 ...

  8. Matplotlib绘图设置---文字和标签

    文字和文字位置 通过plt.text()或ax.text()命令可在图形上添加文字. Signature: ax.text(x, y, s, fontdict=None, withdash=<d ...

  9. HarmonyOS网络管理开发—HTTP与WebSocket

      一.  网络管理开发概述 网络管理模块主要提供以下功能: ● HTTP数据请求:通过HTTP发起一个数据请求. ● WebSocket连接:使用WebSocket建立服务器与客户端的双向连接. ● ...

  10. WEB 版的报表工具有没有意义?

    这个问题得从两个方面看. 如果这个 web 版的报表工具指的是现在的自助报表,也就是 BI.多维分析,那它是有意义的, 而且各厂商们都已经做的挺好,可以让业务人员通过简单的拖拽进行各种数据分析,生成自 ...