设计模式|观察者模式

  • 观察者模式是一种行为设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当主题对象发生变化时,它的所有观察者都会收到通知并更新。观察者模式常用于实现事件处理系统、发布-订阅模式等。
  • 在项目中,我们使用RabbitMQ、Kafka、ActiveMQ等消息中间件来进行解耦、异步、广播、削峰,在设计模式中我们可以使用观察者模式也能达到解耦、异步的特点。下面我将介绍观察者模式。

观察者模式的主要角色

  • Subject(主题):被观察的对象,包含对观察者的引用列表,并提供注册、移除和通知观察者的方法。
  • Observer(观察者):定义一个更新接口,用于接收主题的通知。
  • ConcreteSubject(具体主题):具体的主题,实现了主题接口,状态发生改变时通知所有注册的观察者。
  • ConcreteObserver(具体观察者):具体的观察者,实现了观察者接口,响应主题的变化。

Java 实现观察者模式

下面是一个简单的 Java 观察者模式示例:

1. 定义观察者接口
public interface  Observer {void update(String message);// 处理业务逻辑
}
2. 定义主题接口
public interface  Subject {void registerObserver(Observer observer);// 添加观察者void removeObserver(Observer observer);// 移除观察者void notifyObservers();// 通知所有观察者事件
}
3. 实现具体主题
public class ConcreteSubject implements Subject{private List<Observer> observers;private String message;public ConcreteSubject() {this.observers = new ArrayList<>();}@Overridepublic void registerObserver(Observer observer) {observers.add(observer);}@Overridepublic void removeObserver(Observer observer) {observers.remove(observer);}@Overridepublic void notifyObservers() {for (Observer observer : observers) {observer.update(message);}}public void setMessage(String message) {this.message = message;notifyObservers();}
}
4. 实现具体观察者
public class ConcreteObserver implements Observer {private String name;public ConcreteObserver(String name) {this.name = name;}// 模拟处理业务逻辑@Overridepublic void update(String message) {System.out.println(name + " received message: " + message);}
}
5.测试
public class ObserverPatternDemo {public static void main(String[] args) {ConcreteSubject subject = new ConcreteSubject();Observer observer1 = new ConcreteObserver("Observer 1");Observer observer2 = new ConcreteObserver("Observer 2");Observer observer3 = new ConcreteObserver("Observer 3");subject.registerObserver(observer1);subject.registerObserver(observer2);subject.registerObserver(observer3);System.out.println("----------------------向三个订阅者发送消息 First Message----------------------");subject.setMessage("First Message");System.out.println("----------------------向三个订阅者发送消息 Second Message----------------------");subject.setMessage("Second Message");System.out.println("----------------------依次一个订阅者并发送消息 Third Message-------------------------");subject.removeObserver(observer2);subject.setMessage("Third Message");}
}
6.结果image.png
7.分析
  • 在这里我们可以看到,我们已经可以做到可以向多个订阅者发送消息,而只需要创建一个新的订阅者放入observers容器里面,从而达到解耦的目的。

  • 而要达到异步的功能,可以利用java的并发工具,比如线程、“ExecutorService”等。下面给出实现思路:

1.使用 ExecutorService:

使用 Executors.newCachedThreadPool() 创建一个可缓存的线程池。可以使用其他类型的线程池,如 FixedThreadPool 或 SingleThreadExecutor,根据具体需求选择。

2.异步通知:

在 notifyObservers 方法中,通过 executorService.submit() 提交任务,使得每个观察者的 update 方法在单独的线程中执行,达到了异步通知的效果。

3.资源管理:

在合适的时候调用 executorService.shutdown() 来关闭线程池,确保资源得到释放。通过这种方式,实现了观察者模式的异步通知,使得观察者的 update 方法可以并发执行,提高了效率,避免了通知过程中阻塞的问题。

观察者模式在框架中的应用

1. Java Swing

Java Swing 中的事件处理模型大量使用了观察者模式。按钮点击、窗口关闭等事件的处理都是通过事件监听器实现的。

2. Spring Framework

Spring 框架中也广泛使用了观察者模式,特别是在事件驱动的编程模型中。

  • ApplicationEvent 和 ApplicationListener: Spring 提供了一个事件机制,通过 ApplicationEventApplicationListener 实现观察者模式。
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;@Component
public class MyApplicationListener implements ApplicationListener<ContextRefreshedEvent> {@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {System.out.println("Context Refreshed Event received!");}
}
public class MyCustomEvent extends ApplicationEvent {public MyCustomEvent(Object source) {super(source);}
}@Component
public class MyCustomEventListener implements ApplicationListener<MyCustomEvent> {@Overridepublic void onApplicationEvent(MyCustomEvent event) {System.out.println("Custom Event received!");}
}// 发布事件
@Component
public class MyBean {private final ApplicationEventPublisher publisher;public MyBean(ApplicationEventPublisher publisher) {this.publisher = publisher;}public void publishEvent() {MyCustomEvent event = new MyCustomEvent(this);publisher.publishEvent(event);}
}
3. Google Guava

Google Guava 提供的 EventBus 是一种实现发布-订阅(Pub/Sub)模式的工具,它的实现也是采用设计模式中的观察者设计模式。,它广泛应用于解耦事件生产者和消费者。在 EventBus 中,事件生产者和事件消费者可以彼此独立地工作,彼此无需直接依赖。

观察者模式的优缺点

优点
  1. 解耦:观察者和主题之间是抽象耦合的,可以独立扩展观察者和主题。
  2. 动态订阅:观察者可以在运行时动态添加或移除。
  3. 灵活性:可以在不修改主题类的情况下增加新的观察者,实现了开闭原则。
缺点
  1. 可能引起性能问题:如果观察者较多,通知所有观察者可能会比较耗时。
  2. 可能导致内存泄漏:如果观察者没有及时被移除,可能导致内存泄漏。

使用场景

  1. 事件处理系统:GUI 事件监听,按钮点击事件。
  2. 发布-订阅系统:消息队列,订阅推送服务。
  3. 数据变化通知:数据模型变化通知视图更新,类似于 MVC 模式中的观察者角色

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/48878.shtml

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

相关文章

磁盘管理与磁盘卷--红帽Linux操作系统<>

分区的两种格式 1、MBR分区 MBR(Master Boot Record&#xff0c;主引导记录)是传统的分区机制&#xff0c;使用BI0S引导PC设备&#xff0c;寻址空间只有32bit长。 分区空间最大支持2.2TB 支持的分区数量:4个主分区或者3个主分区1个扩展分区 为什么MBR最多只能有4个主分区?…

云服务部署项目(Spring + Vue)

云计算&#xff1a;腾讯云 操作系统&#xff1a;Ubuntu 22.04.4 LTS 项目&#xff1a;若依前后端分离项目&#xff08;SpringBoot Vue&#xff09; 首先要安装基本的一些依赖环境&#xff0c;大家可以看一下我往期的文章&#xff1a; Ubuntu在线JDK Ubuntu在线安装Nginx Ubunt…

文件解析的终极工具:Apache Tika

文件解析的终极工具&#xff1a;Apache Tika Apache Tika 简介 Apache Tika 是一个开源的、跨平台的库&#xff0c;用于检测、提取和解析各种类型文件的元数据。 它支持多种文件格式&#xff0c;包括文档、图片、音频和视频。 Tika是一个底层库&#xff0c;经常用于搜索引擎…

Android 列表或网格形式展示大量数据:RecyclerView

目录 RecyclerView是什么如何使用RecyclerView 涉及到的类LayoutManager为Item设置不同的布局样式制作拖动的RecyclerView 一、RecyclerView是什么 RecyclerView是Android支持库中的一个控件&#xff0c;用于在列表或网格形式展示大量数据。它是ListView的升级版&#xff0c…

《梦醒蝶飞:释放Excel函数与公式的力量》18.1 图表类型与设计

第18章&#xff1a;创建图表和数据可视化 18.1 图表类型与设计 Excel提供了多种图表类型&#xff0c;帮助用户以直观的方式展示数据。选择合适的图表类型和设计可以显著提高数据的可读性和理解度。以下将介绍常见的图表类型及其应用&#xff0c;并通过具体案例进行说明。 18.…

如何利用Jenkins自动化管理、部署数百个应用

目录 1. Jenkins 安装与部署步骤 1.1 系统要求 1.2 安装步骤 1.2.1 Windows 系统 1.2.2 CentOS 系统 1.3 初次配置 2. Gradle 详细配置方式 2.1 安装 Gradle 2.1.1 Windows 系统 2.1.2 CentOS 系统 2.2 配置 Jenkins 中的 Gradle 3. JDK 详细配置方式 3.1 安装 JD…

Java:防止输入输出超时

一、防止输入超时 当我们直接使用Scanner进行输入操作的时候&#xff0c;每次读取输入的数据都会进行一次硬盘的IO操作&#xff0c;这个操作是很慢的&#xff0c;如果要读取的数据过多&#xff0c;那么我们在刷题网站上就很有可能因为多次的数据读取操作产生超时&#xff01;那…

渠道查问卷调查个人怎么做?

大家好&#xff0c;我是橙河老师&#xff0c;今天讲一讲渠道查问卷调查个人怎么做&#xff1f; 对海外问卷项目有过一些了解的人呢&#xff0c;都应该知道一些渠道查的优势&#xff0c;首先是省去了注册账号、养号一系列的繁琐操作&#xff0c;那通过测题、做题&#xff0c;然…

vscode调试nextjs前端后端程序、nextjs api接口

最近有一个项目使用了nextjs框架&#xff0c;并且使用nextjs同时实现了前后端&#xff0c;由于之前前后端都是分离的&#xff0c;前端的调试可以通过在代码种添加debugger或者直接在浏览器中打断点实现&#xff0c;现在想调试后端接口&#xff0c;前面的方式就不适用了。故研究…

CMA软件实验室评审如何做好人员技术能力的评价?

人员作为实验室的一个重要质量因素&#xff0c;其技术能力和素质水平体现了实验室水平的高低。人员能力是随着时间动态变化的&#xff0c;有效地评价实验室人员的技术能力&#xff0c;是保证实验室活动的必要条件。CMA软件实验室评审也要求实验室要注意对人员能力的监督&#x…

基于web的物流配送管理系统/基于客户时间窗变化的物流配送管理系统/快递配送管理系统

摘 要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时代&a…

性能测试工具、负载测试工具、缺陷跟踪工具推荐

负载测试工具 - 有助于对站点或应用程序进行性能/负载测试 1&#xff09;WebLOAD WebLOAD 是一款出色的测试工具&#xff0c;提供了许多强大的脚本功能&#xff0c;有助于测试复杂场景。该工具支持从 Selenium 到移动端、从企业应用到网络协议的数百种技术。使用这款工具可以…

JAVA.包、final、权限

包 final 权限 代码块 1.构造代码块 创建这个本类的对象的时候会先指向构造代码块再执行构造方法 作用&#xff1a;把构造方法重复的部分抽取出来 2.静态代码块 static 随着类的加载而加载&#xff0c;只执行一次。 作用&#xff1a;数据初始化&#xff0c;比如在学生管…

CSS学习笔记[Web开发]

CSS学习 本文为学习笔记&#xff0c;参考菜鸟和w3c 文章目录 CSS 简介CSS 插入外部 CSS内部 CSS行内 CSS多个样式表层叠顺序 CSS 语法例子解释 CSS 选择器CSS 元素选择器CSS id 选择器实例CSS 类选择器实例CSS 通用选择器实例CSS 分组选择器CSS 后代选择器CSS 子元素选择器CSS …

OnlyOffice社区版部署及前端嵌入使用实现office的docx、xlsx等在线协同编辑预览

一、OnlyOffice介绍 ONLYOFFICE 是一款功能丰富的在线办公软件。它由 Ascensio System SIA 公司开发&#xff0c;有社区版、企业版和开发版等版本。本教程介绍开源社区版的安装使用&#xff0c;实现查看、编辑并协作处理文档、工作表、幻灯片&#xff0c;多人实时协同编辑&…

「树形结构」基于 Antd 实现一个动态增加子节点+可拖拽的树

效果 如图所示 实现 import { createRoot } from react-dom/client; import React, { useState } from react; import { Tree, Input, Button } from antd; import { PlusOutlined } from ant-design/icons;const { TreeNode } Tree; const { Search } Input;const ini…

视频怎么加密?常见的四种视频加密方法和软件

视频加密是一种重要的技术手段&#xff0c;用于保护视频内容不被未经授权的用户获取、复制、修改或传播。在加密过程中&#xff0c;安企神软件作为一种专业的加密工具&#xff0c;可以发挥重要作用。 以下将详细介绍如何使用安企神软件对视频进行加密&#xff0c;并探讨视频加密…

C# 基础语法(一篇包学会的)

C#&#xff08;读作"C Sharp"&#xff09;是一种现代的、通用的面向对象编程语言&#xff0c;由微软公司开发。它结合了C和C的强大特性&#xff0c;并去掉了一些复杂性&#xff0c;使得开发者可以更加高效地编写代码。 一、入坑C# (一) 安装和设置 首先&#xff0c…

Vue 实现电子签名并生成签名图片

目录 前言项目结构代码实现 安装依赖创建签名画布组件生成签名图片 总结相关阅读 1. 前言 电子签名在现代Web应用中越来越普遍&#xff0c;例如合同签署、确认表单等。本文将介绍如何使用Vue.js实现一个简单的电子签名功能&#xff0c;并将签名生成图片。 2. 项目结构 项…

外行对自动驾驶汽车的一些想法-2024-

起源 前段时间有关于自动驾驶汽车的讨论&#xff0c;现在热度终于快过去了。 (⊙﹏⊙) 其实&#xff0c;完全不用担心自动驾驶取代人类。 引用 这是一篇24年4月的报道。 上图为引用&#xff0c;可以看到打工人的忙碌。 2023 一个热爱自动驾驶但妥妥外行之人的思考-2023-C…