观察者模式, 发布-订阅模式, 监听器模式

观察者模式, 发布-订阅模式, 监听器模式

观察者模式

观察者模式是一种行为型设计模式, 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新

角色模型和结构图

在观察者模式中,只有两种主体:目标对象 (Object) 和 观察者 (Observer)。宗门任务大殿就是目标对象,弟子们就是观察者。

  • Subject(主题): 主题是被观察的对象,它维护了一个观察者列表,并提供了添加、删除和通知观察者的方法
  • Observer(观察者): 观察者是订阅主题对象的对象,当主题对象的状态发生变化时,观察者会接收到通知并进行相应的处理。

结构图如下
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

代码实现

观察者抽象接口-Observer
/*** @author whitebrocade* @version 1.0* @description: 抽象观察者接口*/
public interface Observer {/*** 发生改变时发送的message* @param message 发送的message*/void update(Object message);
}
主题-Subject
/*** @author whitebrocade* @version 1.0* @description: 主题*/
public interface Subject {/*** 主题新增观察者* @param observer 要注册的Observer*/void registerObserver(Observer observer);/*** 移除主题下的观察者* @param observer 要移除的Observer*/void removeObserver(Observer observer);/*** 通知该主题所有的Observer* @param message 通知内容*/void notifyObservers(Object message);
}
Observer实现类-User
/*** @author whitebrocade* @version 1.0* @description: 微信公众号的具体观察者即用户User*/
public class User implements Observer {/*** 用户姓名*/private final String name;/*** 接受的消息*/private Object message;public User(String name) {this.name = name;}/*** 确认消息*/public void read() {System.out.println(name + "收到推送消息: " + message);}/*** @param message 发送的message*/@Overridepublic void update(Object message) {this.message = message;read();}
}

####Subject实现类- WechatServer

import java.util.ArrayList;
import java.util.List;/*** @author whitebrocade* @version 1.0* @description: 微信公共号*/
public class WechatServer implements Subject {/*** 存储Observer的列表*/private final List<Observer> observerList;/*** 推送的消息*/private Object message;public WechatServer() {observerList = new ArrayList<>();}/*** @param observer 要注册的Observer*/@Overridepublic void registerObserver(Observer observer) {// 将Observer添加到列表中observerList.add(observer);}/*** @param observer 要移除的Observer*/@Overridepublic void removeObserver(Observer observer) {// 移除observerif (!observerList.isEmpty()) {observerList.remove(observer);}}/*** @param message 通知内容*/@Overridepublic void notifyObservers(Object message) {// 遍历被观察者列表,通知每一个Observerfor (Observer observer : observerList) {// 调用update进行通知observer.update(message);}}/*** 发送微信公众号要推送的消息* @param message 要发送的消息*/public void setInformation(Object message) {this.message = message;System.out.println("微信服务更新消息: " + message);// 消息更新,通知所有观察者notifyObservers(message);}
}
测试类-ObserverModeTest
/*** @author whitebrocade* @version 1.0* @description: Observer测试*/
public class ObserverModeTest {public static void main(String[] args) {WechatServer server = new WechatServer();Observer jack = new User("Jack");Observer smith = new User("Smith");Observer kerry = new User("Kerry");server.registerObserver(jack);server.registerObserver(smith);server.registerObserver(kerry);server.setInformation("蚁钳是蚁钳, 蟹仔是蟹仔!");System.out.println("----------------------------------------------");// 将jack从观察者集合中移除server.removeObserver(jack);server.setInformation("菜就多练, 练就不菜");}
}

测试结果如下
在这里插入图片描述

发布-订阅模式

大概很多人都和我一样,觉得发布订阅模式里的Publisher,就是观察者模式里的Subject,而Subscriber,就是Observer。Publisher变化时,就主动去通知Subscriber。

其实并不是。

在发布订阅模式里,发布者,并不会直接通知订阅者,换句话说,发布者和订阅者,彼此互不相识。之间交流通过Broker进行

角色模型和结构图

  • 发布者(Publisher):负责发布事件或消息到事件总线(Event Bus)中,让订阅者(Subscribers)可以接收到这些事件或消息。
  • EventBus(事件总线):作为发布者和订阅者之间的中介者,负责接收发布者发布的事件,并将事件分发给所有订阅者。事件总线可以是一个独立的组件或者一个消息队列
    • 这里的发布者(事件总线)为一体
  • Subscriber(订阅者): 订阅者订阅感兴趣的消息或事件,并从消息代理中接收相关的消息或事件
  • Event(事件): 事件是发布者发布的消息或事件,订阅者可以根据自己的需求选择订阅特定的事件
    在这里插入图片描述

代码实现

Event
import lombok.Data;/*** @author whitebrocade* @version 1.0* @description: 抽象事件源*/
@Data
public abstract class Event {/*** 事件名*/private String name;/*** 事件信息*/private Object message;/*** 事件信息*/private Object type;
}
Subscriber
/*** @author whitebrocade* @version 1.0* @description: 定义订阅者接口*/
public interface Subscriber {/*** 事件触发后执行的逻辑* @param event 事件*/void handleEvent(Event event);
}
MyEvent
/*** @author whitebrocade* @version 1.0* @description: 自定义事件源*/
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class MyEvent extends Event {/*** 触发时间*/private Date triggerTime;
}
MySubscriber
/*** @author whitebrocade* @version 1.0* @description: 定义具体订阅者*/
public class MySubscriber implements Subscriber {/*** 订阅者名称*/private final String name;public MySubscriber(String name) {this.name = name;}@Overridepublic void handleEvent(Event event) {System.out.println(name + "订阅的事件: " + event.toString());}
}
EventBus
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** @author whitebrocade* @version 1.0* @description: 事件总线*/
public class EventBus {/*** k-v存储订阅者名称和订阅者*/private Map<String, List<Subscriber>> subscriberList = new HashMap<>();/*** 订阅事件* @param eventName 事件名* @param subscriber 订阅者*/public void subscribe(String eventName, Subscriber subscriber) {if (! subscriberList.containsKey(eventName)) {subscriberList.put(eventName, new ArrayList<>());}subscriberList.get(eventName).add(subscriber);}/*** 发布事件* @param event 事件*/public void publish(Event event) {List<Subscriber> eventSubscribers = subscriberList.get(event.getName());if (eventSubscribers != null) {for (Subscriber subscriber : eventSubscribers) {subscriber.handleEvent(event);}}}
}
测试类
import java.util.Date;/*** @author whitebrocade* @version 1.0* @description: 发布-订阅模式测试类*/
public class PublisherTest {public static void main(String[] args) {// 创建事件总线EventBus eventBus = new EventBus();// 创建订阅者Subscriber jack = new MySubscriber("Jack");Subscriber tom = new MySubscriber("Tom");// 订阅事件eventBus.subscribe("event1", jack);eventBus.subscribe("event2", tom);// 发布事件MyEvent event1 = new MyEvent();event1.setName("event1");event1.setTriggerTime(new Date());event1.setMessage("蚁钳是蚁钳, 蟹仔是蟹仔!");event1.setType("消息一");MyEvent event2 = new MyEvent();event2.setName("event2");event2.setTriggerTime(new Date());event2.setMessage("菜就多练, 练就不菜!");event2.setType("消息二");eventBus.publish(event1);eventBus.publish(event2);}
}

测试结果如下
在这里插入图片描述

观察者模式 和 发布-订阅模式的对比

共同点
  1. 解耦性: 两种模式都能实现发布者与订阅者(观察者)之间的解耦,使得发布者和订阅者可以独立地进行扩展和修改,互不影响。
  2. 事件通知: 在两种模式中,发布者(主题)发生变化时会通知订阅者(观察者),订阅者(观察者)会相应地处理这些事件或通知
区别
  1. 通信机制:
    • 观察者模式: 观察者模式是一对多的通信机制,一个主题对象可以有多个观察者对象订阅它,当主题对象状态发生变化时,所有订阅者都会收到通知
    • 发布-订阅模式: 发布-订阅模式是通过一个消息代理(发布者)来进行通信,发布者将消息发送到消息代理,然后由消息代理将消息分发给所有订阅者。订阅者只需订阅感兴趣的事件,而不需要直接与发布者交互
  2. 关系建立:
    • 观察者模式: 在观察者模式中,观察者需要直接订阅主题对象,主题对象需要维护一个观察者列表
    • 发布-订阅模式: 在发布-订阅模式中,发布者和订阅者之间通过一个消息代理(或事件总线Eventg)进行通信,发布者和订阅者之间不直接建立联系
  3. 灵活性:
    • 观察者模式: 观察者模式在订阅关系上是静态的,即订阅者需要直接订阅特定的主题对象
    • 发布-订阅模式: 发布-订阅模式在订阅关系上是动态的,订阅者可以根据需要订阅不同的事件或消息

监听器模式

监听器模式并不是一个新的设计模式,它是观察者模式在特定场景下的一种改造和应用。通常,观察者模式的主题在通知观察者时,通知中不包含任何信息。如果这个过程中携带了一些其他信息,那么主题本身就成为了事件源,而携带信息的封装类就成为了事件。此时的观察者模式,也就升级为监听器了。监听器模式是观察者模式的另一种形态

角色模型和结构图

监听器模式通常包含三个角色:事件源、事件对象、事件监听器

  • 事件源: 被监听的事件本身, 也就是可以触发监听器的某件事件
  • 事件对象: :事件对象里面存放了对事件源的引用, 可以通过事件对象来获取事件源, 是对事件源的包装
  • 事件监听器: 定义事件发生后的动作

代码实现

Event
import lombok.Data;/*** @author whitebrocade* @version 1.0* @description: 抽象事件源*/
@Data
public abstract class Event {/*** 事件信息*/private Object message;/*** 事件信息*/private Object type;
}
EventListener
/*** @author whitebrocade* @version 1.0* @description: 监听器接口*/
public interface EventListener {/*** 事件触发时回调* @param event 事件*/void onEventReceived(Event event);
}
EventSource
/*** @author whitebrocade* @version 1.0* @description: 事件源类, 用于注册监听器、触发事件并通知所有监听器*/
public interface EventSource {/*** 注册事件监听器* @param listener 监听器*/void addListener(EventListener listener);/*** 移除监听器* @param listener 监听器*/void removeListener(EventListener listener);/*** 事件分发器, 将事件传递给所有注册的事件监听器* @param event 事件*/void fireEvent(Event event);
}
MyEvent
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.util.Date;/*** @author whitebrocade* @version 1.0* @description: 自定义事件源*/
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class MyEvent extends Event {/*** 触发时间*/private Date triggerTime;
}
MyListener
/*** @author whitebrocade* @version 1.0* @description: 事件监听器*/
public class MyListener implements EventListener {@Overridepublic void onEventReceived(Event event) {System.out.println("收到的事件: " + event.toString());}
}
MyEventSource
import java.util.ArrayList;
import java.util.List;/*** @author whitebrocade* @version 1.0* @description: 事件源类, 用于注册监听器、触发事件并通知所有监听器*/
public class MyEventSource implements EventSource {/*** 事件源集合*/private List<EventListener> listenerList = new ArrayList<>();/*** 注册事件监听器* @param listener 监听器*/public void addListener(EventListener listener) {listenerList.add(listener);}/*** 移除监听器* @param listener 监听器*/public void removeListener(EventListener listener) {listenerList.remove(listener);}/*** 事件分发器, 将事件传递给所有注册的事件监听器* @param event 事件*/public void fireEvent(Event event) {for (EventListener listener : listenerList) {listener.onEventReceived(event);}}
}
ListenerTest
import java.util.Date;/*** @author whitebrocade* @version 1.0* @date 2024/2/21 21:24* @description: TODO*/
public class ListenerTest {public static void main(String[] args) {// 创建一个事件源EventSource eventSource = new MyEventSource();// 创建两个事件监听器MyListener listener1 = new MyListener();MyListener listener2 = new MyListener();// 将这两个事件监听器注册到事件源eventSource.addListener(listener1);eventSource.addListener(listener2);// 创建一个事件eventMyEvent event = new MyEvent();event.setTriggerTime(new Date());event.setMessage("蚁钳是蚁钳, 蟹仔是蟹仔!");event.setType("消息一");// 将事件传递给事件源, 进行分发eventSource.fireEvent(event);// 从事件源中移除一个listener2事件监听器eventSource.removeListener(listener2);// 再次创建一个事件event2MyEvent event2 = new MyEvent();event2.setTriggerTime(new Date());event2.setMessage("菜就多练, 练就不菜!");event2.setType("消息二");// 将事件传递给事件源, 进行分发eventSource.fireEvent(event2);}
}

测试结果如下
在这里插入图片描述

参考资料

观察者模式 vs 发布订阅模式,千万不要再混淆了

观察者模式 | 菜鸟教程

23 种设计模式详解(全23种)-观察者模式

观察者 - 廖雪峰的官方网站

监听器模式和观察者模式的关系,写点你不知道的

【设计模式】-11监听者模式

【设计模式】-监听者模式和观察者模式的区别与联系_观察者模式和监听者模式的区别

观察者模式 vs 发布订阅模式

[设计模式(四) —— 观察者模式/发布订阅模式](https://blog.csdn.net/weixin_37620587/article/details/130170062#:~:text=1.什么是发布-订阅模式 1 发布-订阅模式是一种行为设计模式,它允许多个对象通过事件的发布和订阅来进行通信; 2,在这种模式中,发布者 (又称为主题)负责发布事件,而订阅者 (也称为观察者)则通过订阅主题来接收这些事件; 3 这种模式使得应用程序的不同部分能够松散耦合,并且可以动态地添加或删除订阅者;)

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

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

相关文章

HarmonyOS Stage模型基本概念讲解

本文 我们来说harmonyos中的一种应用模型 Stage模型 官方提供了两种模型 一种是早期的 FA模型 另一种就是就是 harmonyos 3.1才开始的新增的一种模型 Stage模型 目前来讲 Stage 会成为现在乃至将来 长期推进的一种模型 也就是 无论是 现在的harmonyos 4.0 乃至 之后要发布的 …

IP地理位置查询定位:技术原理与实际应用

在互联网时代&#xff0c;IP地址是连接世界的桥梁&#xff0c;而了解IP地址的地理位置对于网络管理、个性化服务以及安全监控都至关重要。IP数据云将深入探讨IP地理位置查询定位的技术原理、实际应用场景以及相关的隐私保护问题&#xff0c;旨在为读者提供全面了解和应用该技术…

印刷机械故障诊断:虹科MSR165助力Müller Martini AG成功案例

在为杂志装订机开发新产品的过程中&#xff0c;作为印刷后处理机械领域的全球领导者&#xff0c;Mller Martini AG公司发现了传感器故障的问题。通过使用虹科MSR 微型加速度数据记录仪&#xff0c;成功地确定了故障的原因。 新杂志装订机中的三刀修整装置的故障部件是边缘传感器…

BOSS直聘招聘经验

招聘低端兼职岗位。流量很大&#xff0c;来的人通常实力也不足。 招聘高端兼职岗位。流量不多。来的人通常具备一定实力。 招聘高薪职位&#xff0c;流量一般&#xff0c;会有有实力的勾搭。 招聘低薪职位&#xff0c;流量一般。通常没什么实力。

使用 Optimum Intel 在英特尔至强上加速 StarCoder: Q8/Q4 及投机解码

引言 近来&#xff0c;随着 BigCode 的 StarCoder 以及 Meta AI 的 Code Llama 等诸多先进模型的发布&#xff0c;代码生成模型变得炙手可热。同时&#xff0c;业界也涌现出了大量的致力于优化大语言模型 (LLM) 的运行速度及易用性的工作。我们很高兴能够分享我们在英特尔至强 …

测试多线程架构的问题

在测试多线程架构时&#xff0c;需要考虑多个方面以确保系统的稳定性和性能。以下是一些关键问题&#xff0c;需要在测试过程中特别关注&#xff1a; 线程同步 多线程环境中&#xff0c;线程同步是非常重要的问题。由于多个线程可能同时访问共享资源&#xff0c;因此需要使用…

Linux环境下查看磁盘层级占用空间的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

C++从入门到精通 第十三章(认识STL)

写在前面&#xff1a; 本系列专栏主要介绍C的相关知识&#xff0c;思路以下面的参考链接教程为主&#xff0c;大部分笔记也出自该教程&#xff0c;笔者的原创部分主要在示例代码的注释部分。除了参考下面的链接教程以外&#xff0c;笔者还参考了其它的一些C教材&#xff08;比…

下一代自动化爬虫神器--playwright,所见即所得,配合逆向不要太香!!!

文章目录 1.Playwright介绍2.与 Selenium 和 pyppeteer 相比&#xff0c;Playwright 具有以下几个区别和优势3.在爬虫中使用 Playwright 的好处4.环境安装5.屏幕录制6.保留记录cookie信息7.playwright代码编写详解1.第一个Playwright脚本&#xff08;1&#xff09;同步模式&…

Redis之缓存穿透问题解决方案实践SpringBoot3+Docker

文章目录 一、介绍二、方案介绍三、Redis Docker部署四、SpringBoot3 Base代码1. 依赖配置2. 基本代码 五、缓存优化代码1. 校验机制2. 布隆过滤器3. 逻辑优化 一、介绍 当一种请求&#xff0c;总是能越过缓存&#xff0c;调用数据库&#xff0c;就是缓存穿透。 比如当请求一…

阿里云国际站如何助力餐饮行业出海?

近些年&#xff0c;中国企业出海方兴未艾。全球不同国家的经济政治诉求加剧了商业领域的博弈&#xff0c;全球产业供应链格局持续发生深刻变化。无论是海外建厂&#xff0c;还是海外找市场&#xff0c;中国产业链的全球布局蔚然成风,企业想突破现阶段瓶颈&#xff0c;谋求更好的…

⭐北邮复试刷题106. 从中序与后序遍历序列构造二叉树__递归分治 (力扣每日一题)

106. 从中序与后序遍历序列构造二叉树 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1: 输入&#xff1a;inorder [9,3,15,20,7], postor…

ros自定义action记录

文章目录 自定义action1. 定义action文件2. 修改 package.xml3. 修改 CMakeLists.txt4. 运行 catkin build5. simple_action_server.py6. simple_action_client.py 测试 自定义action ros 版本&#xff1a;kinetic 自定义test包的文件结构如下 |-- test | |-- CMakeLists.t…

Internet Download Manager 6.42.3 (IDM) 中文免激活绿色版

相信很多网友都遇到过一种情况&#xff0c;网页有些视频资源或者音频资源不知道如何下载&#xff0c;一直不知道如何解决&#xff0c;为此小编特意带来了这款&#xff1a;Internet Download Manager电脑版&#xff0c;这是一款非常专业且十分好用的下载工具&#xff0c;也就是大…

Android 11以上获取不到第三方app是否安装

开年第一篇&#xff0c;处理了一下年前的小问题。 问题&#xff1a;本地app跳转到第三方app地图进行导航&#xff0c;获取不到第三方地图是否安装。 解决&#xff1a; 1.添加包名 This can be done by adding a <queries> element in the Android manifest.在app下的…

1408: [宁波25届]方格稿纸

题目描述 小猪在小学中认识了很多的字&#xff0c;终于会写一点作文了。某天小猪买了一张方格稿纸来写作文,n 行m 列,形状如下所示&#xff1a; 上图中nm5 。 某天小猪的邻居小小猪来小猪家玩&#xff0c; 用黑墨水笔把小猪新买的方格稿纸涂黑了很多格子。 每个格子不是完全黑…

psp游戏存档收集SAVEDATA

不想从头开始 ppsspp存档目录 pc&#xff1a;ppsspp解压目录\memstick\PSP\SAVEDATA 安卓&#xff1a;根目录\PSP\SAVEDATA 噬神者2(日版) NPJH50832099c645531020001000 風燐-https://wwl.lanzouq.com/iI1R01owozxa 咲夜-https://wwl.lanzouq.com/id1tX1owp2uf につてのぬ…

华为笔记本原厂系统镜像恢复安装教程方法

1.安装方法有两种&#xff0c;一种是用PE安装&#xff0c;一种是华为工厂包安装&#xff08;安装完成自带F10智能还原&#xff09; 若没有原装系统文件&#xff0c;请在这里远程恢复安装&#xff1a;https://pan.baidu.com/s/166gtt2okmMmuPUL1Fo3Gpg?pwdm64f 提取码:m64f …

Pormise---如何解决javascript中回调的信任问题?【详解】

本人编程小白一枚&#xff0c;希望多多包涵~ 如果阅读有疑问的话&#xff0c;欢迎评论或私信&#xff01;&#xff01; 本人会很热心的阐述自己的想法&#xff01;谢谢&#xff01;&#xff01;&#xff01; 文章目录 回调中的信任问题回调给我们带来的烦恼&#xff1f;调用过早…

【深度学习:对象跟踪】对象跟踪完整指南 [教程]

【深度学习&#xff1a;对象跟踪】对象跟踪完整指南 [教程] 什么是计算机视觉中的对象跟踪&#xff1f;对象跟踪有哪些不同类型&#xff1f;图像跟踪视频跟踪单目标跟踪多对象跟踪 计算机视觉中对象跟踪的用例监测零售自动驾驶汽车医疗保健 对象跟踪方法步骤 1&#xff1a;目标…