设计模式基础概念(行为模式):观察者模式(Observer)

概述

我们可以发现这样一个场景:如果你订阅了一份杂志或报纸, 那就不需要再去报摊查询新出版的刊物了。

  • 出版社 (即应用中的 “发布者(publisher)”) 会在刊物出版后 (甚至提前) 直接将最新一期寄送至你的邮箱中。

    出版社负责维护订阅者(subscribers)列表, 了解订阅者对哪些刊物感兴趣。

  • 当订阅者希望出版社停止寄送新一期的杂志时, 他们可随时从该列表中退出。

观察者模式(Observer)是一种行为设计模式, 允许你定义一种订阅机制, 可在对象事件发生时通知多个 “观察” 该对象的其他对象

  • 拥有一些值得关注的状态的对象通常被称为目标
  • 由于它要将自身的状态改变通知给其他对象, 我们也将其称为发布者 (publisher)
  • 所有希望关注发布者状态变化的其他对象被称为订阅者 (subscribers)

结构如下

其具体的结构如下
在这里插入图片描述

场景选择

当一个对象状态的改变需要改变其他对象, 或实际对象是事先未知的或动态变化的时, 可使用观察者模式。

  • 当你使用图形用户界面类时通常会遇到一个问题。

    比如, 你创建了自定义按钮类并允许客户端在按钮中注入自定义代码, 这样当用户按下按钮时就会触发这些代码。

  • 观察者模式允许任何实现了订阅者接口的对象订阅发布者对象的事件通知。

    可在按钮中添加订阅机制, 允许客户端通过自定义订阅类注入自定义代码。

当应用中的一些对象必须观察其他对象时, 可使用该模式。 但仅能在有限时间内或特定情况下使用

  • 订阅列表是动态的, 因此订阅者可随时加入或离开该列表

目前代码中的实际应用

应用示例: 观察者模式在 Java 代码中很常见, 特别是在 GUI 组件中。 它提供了在不与其他对象所属类耦合的情况下对其事件做出反应的方式

下面是核心 Java 程序库中该模式的一些示例:

  • java.util.Observer/java.util.Observable (极少在真实世界中使用)
  • java.util.EventListener的所有实现 (几乎广泛存在于 Swing 组件中)
  • javax.servlet.http.HttpSessionBindingListener
  • javax.servlet.http.HttpSessionAttributeListener
  • javax.faces.event.PhaseListener

识别方法加粗样式: 该模式可以通过将对象存储在列表中的订阅方法, 和对于面向该列表中对象的更新方法的调用来识别

伪代码实现

发布者 (Publisher)

发布者 (Publisher) 会向其他对象发送值得关注的事件

  • 事件会在发布者自身状态改变或执行特定行为后发生
  • 发布者中包含一个允许新订阅者加入和当前订阅者离开列表的订阅构架
  • 新事件发生时, 发送者会遍历订阅列表并调用每个订阅者对象的通知方法。 该方法是在订阅者接口中声明的

示例代码

// 保存所有订阅此主题的观察者,观察者的 数量是任意的。
// 定义 添加观察者 (Attach) 和 删除观察者 (Detach) 的接口。
abstract class Publisher {protected String name;protected String state;protected List<Subscriber> subscribers = new ArrayList<Subscriber>();public abstract String getState();public abstract void setState(String state);// 发布public abstract void Notify();public Publisher(String name) {this.name = name;}// 添加观察者public void Attach(Subscriber subscriber) {observers.add(observer);}//  删除观察者public void Detach(Subscriber subscriber) {observers.remove(observer);}
}

订阅者 (Subscriber)

订阅者 (Subscriber) 接口声明了通知接口

  • 绝大多数情况下, 该接口仅包含一个 update更新方法
  • 该方法可以拥有多个参数, 使发布者能在更新时传递事件的详细信息

示例代码

// 观察者类,定义更新接口 (Update),当收到 Subject 的通知时,Observer 需要同步更新信息
abstract class Subscriber {protected String name;// 监听的发布者protected Publisher publisher;public Subscriber(String name, Publisher publisher) {this.name = name;this.publisher= publisher;}public abstract void Update();
}

上下文信息

订阅者通常需要一些上下文信息来正确地处理更新。

  • 因此, 发布者通常会将一些上下文数据作为通知方法的参数进行传递
  • 发布者也可将自身作为参数进行传递, 使订阅者直接获取所需的数据

如上示例所示,上下文信息便是status和name

具体发布者 (Concrete Publisher)

具体发布者 (Concrete Publisher)相当于订阅者需要监听的类型(因为这个类型有很多种,大部分情况下不可能只有一种发布者)

示例代码

class ConcretePublisher extends Publisher{public ConcretePublisher(String name) {super(name);}@Overridepublic String getState() {return state;}@Overridepublic void setState(String state) {this.state = state;}@Overridepublic void Notify() {System.out.println("======= " + this.name + "主题发布新消息 =======");for (Subscriber subscriber : subscribers) {subscriber.Update();}}
}

具体订阅者类(Concrete Subscriber )

具体订阅者 (Concrete Subscribers) 可以执行一些操作来回应发布者的通知

  • 所有具体订阅者类都实现了同样的接口, 因此发布者不需要与具体类相耦合。

ConcreteSubscriber : 具体订阅者类,实现 Subscriber 的更新接口 (Update),以便和 Publisher 同步状态信息

示例代码

class ConcreteSubscriber extends Subscriber {private String state;public ConcretePublisher(String name, Publisher publisher) {super(name, publisher);}@Overridepublic void Update() {state = subject.getState();System.out.println(this.name + "收到当前状态:" + state);}
}

客户端 (Client)

客户端 (Client) 会分别创建发布者和订阅者对象, 然后为订阅者注册发布者更新

示例代码

public class ObserverPattern {public static void main(String[] args) {ConcretePublisher concretePublisher = new ConcretePublisher("天气");ConcreteSubscriber sub1 = new ConcreteSubscriber("张三", concretePublisher);ConcreteSubscriber sub2= new ConcreteSubscriber("李四", concretePublisher);ConcreteSubscriber sub3= new ConcreteSubscriber("王五", concretePublisher);concretePublisher.Attach(sub1);concretePublisher.Attach(sub2);concretePublisher.Attach(sub3);concretePublisher.setState("今天下雨");concretePublisher.Notify();concretePublisher.Detach(sub2);concretePublisher.setState("明天天晴");concretePublisher.Notify();}
}
/*
======= 天气主题发布新消息 =======
张三收到当前状态:今天下雨
李四收到当前状态:今天下雨
王五收到当前状态:今天下雨
======= 天气主题发布新消息 =======
张三收到当前状态:明天天晴
王五收到当前状态:明天天晴*/

实现方式

下面总结一下实现的步骤,大致可分为下面的几步

  1. 仔细检查业务逻辑, 试着将其拆分为两个部分:

    1. 独立于其他代码的核心功能将作为发布者
    2. 其他代码则将转化为一组订阅类
  2. 声明订阅者接口。 该接口至少应声明一个 update方法

  3. 声明发布者接口并定义一些接口来在列表中添加和删除订阅对象。

    1. 记住发布者仅通过订阅者接口与它们进行交互
  4. 确定存放实际订阅列表的位置并实现订阅方法

    1. 通常所有类型的发布者代码看上去都一样, 因此将列表放置在直接扩展自发布者接口的抽象类中是显而易见的。 具体发布者会扩展该类从而继承所有的订阅行为
    2. 但是, 如果你需要在现有的类层次结构中应用该模式, 则可以考虑使用组合的方式: 将订阅逻辑放入一个独立的对象, 然后让所有实际订阅者使用该对象。
  5. 创建具体发布者类。 每次发布者发生了重要事件时都必须通知所有的订阅者。

  6. 在具体订阅者类中实现通知更新的方法

    1. 绝大部分订阅者需要一些与事件相关的上下文数据。 这些数据可作为通知方法的参数来传递。
    2. 但还有另一种选择。 订阅者接收到通知后直接从通知中获取所有数据。 在这种情况下, 发布者必须通过更新方法将自身传递出去。 另一种不太灵活的方式是通过构造函数将发布者与订阅者永久性地连接起来。
  7. 客户端必须生成所需的全部订阅者, 并在相应的发布者处完成注册工作。

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

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

相关文章

JavaFX实战:从零到一实现一个功能丰富的“高级反应速度测试”游戏

大家好&#xff01;今天我们不搞简单的“红变绿就点”了&#xff0c;来点硬核的&#xff01;我们要用 JavaFX 从头开始&#xff0c;构建一个更复杂、更有趣也更考验能力的“高级反应速度测试”游戏。这个版本将引入选择反应时 (Choice Reaction Time) 的概念——你需要在多个干…

CSS 选择器介绍

CSS 选择器介绍 1. 基本概念 CSS&#xff08;层叠样式表&#xff09;是一种用于描述 HTML 或 XML 文档外观的语言。通过 CSS&#xff0c;可以控制网页中元素的布局、颜色、字体等视觉效果。而 CSS 选择器则是用来指定哪些 HTML 元素应该应用这些样式的工具。 2. 基本选择器 …

Vue3父子组件数据同步方法

在 Vue 3 中&#xff0c;当子组件需要修改父组件传递的数据副本并同步更新时&#xff0c;可以通过以下步骤实现&#xff1a; 方法 1&#xff1a;使用 v-model 和计算属性&#xff08;实时同步&#xff09; 父组件&#xff1a; vue <template><ChildComponent v-mo…

el-table中el-input的autofocus无法自动聚焦的解决方案

需求 有一个表格展示了一些进度信息&#xff0c;进度信息可以修改&#xff0c;需要点击进度信息旁边的编辑按钮时&#xff0c;把进度变为输入框且自动聚焦&#xff0c;当鼠标失去焦点时自动请求更新接口。 注&#xff1a;本例以vue2 element UI为例 分析 这个需求看着挺简单…

用高斯溅射技术跨越机器人模拟与现实的鸿沟:SplatSim 框架解析

在机器人领域&#xff0c;让机器人在现实世界中精准执行任务是大家一直追求的目标。可模拟环境和现实世界之间存在着不小的差距&#xff0c;特别是基于 RGB 图像的操作策略&#xff0c;从模拟转移到现实时总是状况百出。 今天咱们就来聊聊 SplatSim 框架&#xff0c;看看它是怎…

【自然语言处理与大模型】如何知道自己部署的模型的最大并行访问数呢?

当你自己在服务器上部署好一个模型后&#xff0c;使用场景会有两种。第一种就是你自己去玩&#xff0c;结合自有的数据做RAG等等&#xff0c;这种情况下一般是不会考虑并发的问题。第二种是将部署好的服务给到别人来使用&#xff0c;这时候就必须知道我的服务到底支持多大的访问…

[FPGA基础] UART篇

Xilinx FPGA UART 硬件接口使用指南 1. 引言 UART (通用异步收发器) 是一种广泛使用的串行通信接口&#xff0c;因其简单、可靠和易于实现而成为 Xilinx FPGA 设计中的常见硬件接口。UART 用于在 FPGA 与外部设备&#xff08;如 PC、微控制器、传感器等&#xff09;之间进行数…

【Netty4核心原理】【全系列文章目录】

文章目录 一、前言二、目录 一、前言 本系列虽说本意是作为 《Netty4 核心原理》一书的读书笔记&#xff0c;但在实际阅读记录过程中加入了大量个人阅读的理解和内容&#xff0c;因此对书中内容存在大量删改。 本系列内容基于 Netty 4.1.73.Final 版本&#xff0c;如下&#xf…

用 PyTorch 和numpy分别实现简单的 CNN 二分类器

作业用到的知识&#xff1a; 1.Pytorch: 1. nn.Conv2d&#xff08;二维卷积层&#xff09; 作用&#xff1a; 对输入的多通道二位数据&#xff08;如图像&#xff09;进行特征提取&#xff0c;通过滑动卷积核计算局部区域的加权和&#xff0c;生成新的特征图。 关键参数&a…

使用n8n构建自动化工作流:从数据库查询到邮件通知的使用指南

n8n是一款强大的开源工作流自动化工具&#xff0c;可以帮助你将各种服务和应用程序连接起来&#xff0c;创建复杂的自动化流程。下面我将详细介绍一个实用的n8n用例&#xff1a;从MySQL数据库查询数据并发送邮件通知&#xff0c;包括使用场景、搭建步骤和节点部署方法。 使用场…

Vscode已经打开的python项目,如何使用已经建立的虚拟环境

在 VS Code 中使用已创建的 Conda/Mamba 虚拟环境 pe100&#xff0c;只需以下几步&#xff1a; 步骤 1&#xff1a;确保虚拟环境已存在 在终端运行以下命令&#xff0c;检查 pe100 环境是否已正确创建&#xff1a; conda activate pe100 python --version # 应显示 Python 3…

Volatility工具学习

背景 VMware虚拟机系统hang死&#xff0c;手动重启无法触发系统panic&#xff0c;从而不能触发kdump产生vmcore文件进行原因分析&#xff1b;此种情况下需要手动生成虚拟机内存快照&#xff0c;进而利用Volatility工具分析系统hang死的具体原因。 配置 使用VMware创建虚拟机…

学习笔记(C++篇)--- Day 4

目录 1.赋值运算符重载 1.1 运算符重载 1.2 赋值运算符重载 1.3 日期类实现 1.赋值运算符重载 1.1 运算符重载 ①当运算符被用于类类型的对象时&#xff0c;C语言允许我们通过通过运算符重载的形式指定新的含义。C规定类类型对象使用运算符时&#xff0c;必须转换成调用对…

Docker 快速入门教程

1. Docker 基本概念 镜像(Image): 只读模板&#xff0c;包含创建容器的指令 容器(Container): 镜像的运行实例 Dockerfile: 用于构建镜像的文本文件 仓库(Repository): 存放镜像的地方&#xff08;如Docker Hub&#xff09; 2. 安装Docker 根据你的操作系统选择安装方式:…

vue项目中使用tinymce富文本编辑器

vue使用tinymce 文章目录 vue使用tinymcetinymce富文本编辑器在这里插入图片描述 一、本文要实现二、使用步骤1.安装tinymce2.tinymce组件新建3. 在store添加商品详情的状态管理4. tinymce组件的引入 tinymce富文本编辑器 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下…

简单适配torch_npu不支持的ATen算子

简单适配torch_npu不支持的ATen算子 一、背景说明1.1 PyTorch扩展机制1.2 核心概念二、实现步骤详解2.1 实现前向、反向传播算子2.2 编译生成动态库2.3 测试验证程序三、关键点解析3.1 设计注意事项3.2 性能优化方向四、验证结果一、背景说明 1.1 PyTorch扩展机制 PrivateUse1…

同样的html标记,不同语言的文本,显示的字体和粗细会不一样吗

同样的 HTML 标记&#xff0c;在不同语言的文本下&#xff0c;显示出来的字体和粗细确实可能会不一样&#xff0c;原因如下&#xff1a; &#x1f30d; 不同语言默认字体不同 浏览器字体回退机制 CSS 里写的字体如果当前系统不支持&#xff0c;就会回退到下一个&#xff0c;比如…

基于 Spring Boot 瑞吉外卖系统开发(六)

基于 Spring Boot 瑞吉外卖系统开发&#xff08;六&#xff09; 菜品列表 在系统管理端首页&#xff0c;单击左侧菜单栏中的“菜品管理”&#xff0c;会在右侧打开菜品管理页面。 请求URL/dish/page&#xff0c;请求方法GET,请求参数page&#xff0c;pageSize。 该菜品列表…

计算机视觉与深度学习 | TensorFlow基本概念与应用场景:MNIST 手写数字识别(附代码)

TensorFlow 基本概念 TensorFlow 是一个开源的机器学习框架,由 Google 开发,核心概念包括: 张量(Tensor):多维数组,是数据的基本单位。计算图(Graph):早期版本中用于描述数据流和计算过程,2.x 默认启用即时执行(Eager Execution),兼顾灵活性和性能。层(Layers)…

vue+django+LSTM微博舆情分析系统 | 深度学习 | 食品安全分析

文章结尾部分有CSDN官方提供的学长 联系方式名片 文章结尾部分有CSDN官方提供的学长 联系方式名片 关注B站&#xff0c;有好处&#xff01; 编号&#xff1a; D031 LSTM 架构&#xff1a;vuedjangoLSTMMySQL 功能&#xff1a; 微博信息爬取、情感分析、基于负面消极内容舆情分析…