“遥遥领先”的观察者模式

news2024/9/21 18:54:40

前提

观察者模式是我们在开发时经常会用到的模式,最近在维护公司项目时看见了前辈的代码用到了观察者模式。就想来和大家讲解观察者模式

观察者模式

生搬硬套概念肯定会让我们新手很难理解,刚好最近华为手机出新机了,一机难抢,我们就拿这个事情来做案例吧。

自从华为的新手机发布后,就遭到了大家的疯狂抢购,导致供不应求。你问我为什么?那当然是国产芯片遥遥领先的功劳。

因为很多人想买,但是手机库存不足,所以我们的某宝就推出了订阅模式,当我们的用户添加订阅后,一但有新的手机到货发售,就会通知我们添加订阅的用户。但是要通过什么方式通知呢?当然是需要用户留下自己的手机号码,然后平台才能通过用户的手机号码发送短信通知用户。

那么在用户订阅的功能中有两类主体

  • 某宝(售卖平台)
    • 点击了添加订阅的用户名单列表
    • 订阅了的用户名单列表添加新的订阅用户的功能
    • 通知订阅名单上的用户的功能
    • 当已订阅用户,取消订阅的功能
  • 想要买华为手机的用户
    • 自己的手机号码

那你可能会问这和观察者模式有什么关系?

那关系可大了,某宝和用户之间的订阅通知关系,就是用到了观察模式的设计思路。

你可能还会问那什么是观察者模式呢?

当对象之间存在一对多的依赖关系时,其中一个对象的状态发生改变,所有依赖它的对象都会收到通知,这就是观察者模式。

在观察者模式中,只有两种主体:目标对象 (Object)观察者 (Observer)。华为手机就是目标对象,想买手机的用户就是观察者

  • 目标对象 Subject:

    • 维护观察者列表 observerList ———— 点击了添加订阅的用户名单列表
    • 定义添加观察者的方法 ———— 订阅了的用户名单列表添加新的订阅用户的功能
    • 当自身发生变化后,通过调用自己的 notify 方法依次通知每个观察者执行 update 方法 ———— 通知订阅名单上的用户的功能
  • 观察者 Observer

    • 需要实现 update 方法,供目标对象调用。
    • update方法中可以执行自定义的业务逻辑
    • 用户收到通知后去平台购买手机。

定义

当你使用观察者模式时,你可以创建一个对象(称为主题或发布者),并允许其他对象(称为观察者或订阅者)订阅该主题。当主题状态发生变化时,所有订阅该主题的观察者都会收到通知。

// 主题(Subject)或发布者对象(某宝平台)
class TaobaoStore {
  constructor() {
    this.observers = []; // 存储订阅的用户名单
  }

  // 当有新的用户点击了添加订阅,添加到我们的订阅用户名单
  addObserver(observer) {
    this.observers.push(observer);
  }

  // 当已经买到手机的用户,点击取消订阅时,从订阅的用户名单中移除
  removeObserver(observer) {
    this.observers = this.observers.filter(obs => obs !== observer);
  }

  // 通过用户自己的手机号码给所有的用户发信息,通知所有订阅了的用户
  notifyObservers() {
    this.observers.forEach(observer => {
      observer.update(this);
    });
  }
  
  // 当有新的手机到货时,通知所有用户 
  someStateChanged() {
    // 执行状态变化后的操作...
    // 然后通知观察者
    this.notifyObservers();
  }
}


// 观察者(Observer)(想要买手机的用户)
class Observer {
  constructor(name) {
    this.name = name;
  }

  // 接收到通知时,去购买手机或执行相应操作
  update(subject) {
    console.log(`${this.name} 收到到货通知,可以去购买手机了`);
    // 在这里可以执行一些相应的操作,比如跳转到购买页面等
  }
}

// 使用示例
const taobao = new TaobaoStore();

const user1 = new Observer('用户A');
const user2 = new Observer('用户B');

taobao.addObserver(user1);
taobao.addObserver(user2);

// 模拟新手机到货通知
taobao.someStateChanged();
// 输出:
// 用户A 收到到货通知,可以去购买手机了
// 用户B 收到到货通知,可以去购买手机了

// 移除用户A的订阅
taobao.removeObserver(user1);

// 再次模拟新手机到货通知
taobao.someStateChanged();
// 输出:
// 用户B 收到到货通知,可以去购买手机了

图解结构

image.png

这是一个基本的观察者模式的实现示例。主题对象(Subject)负责管理观察者列表,并在状态发生变化时通知观察者。观察者对象(Observer)订阅主题,并在接收到通知时执行相应的操作。

优点和缺点

优点:

  1. 松散耦合:观察者模式允许主题(被观察者)和观察者(订阅者)之间保持松散耦合,主题并不需要知道观察者的具体细节,只需要知道观察者实现了特定的接口或方法即可。这使得系统中的对象之间的交互更灵活、可扩展性更强。
  2. 发布-订阅模式:观察者模式类似于发布-订阅模式,它允许多个观察者订阅同一个主题,并在主题状态发生变化时接收通知。这种模式有助于在分布式系统中实现消息传递和事件驱动的架构。
  3. 可扩展性:由于松散耦合的特性,可以随时增加或移除观察者,而不需要对主题对象进行修改。这样做对系统的可扩展性有很大帮助,可以根据需要动态添加新的观察者。
  4. 模块化设计:观察者模式支持模块化设计,每个观察者可以专注于自己的任务,主题对象负责管理状态变化并通知观察者,从而使系统更易于维护和管理。

缺点:

  1. 可能引起性能问题:如果通知过于频繁,观察者模式可能导致性能问题。当主题对象有大量观察者时,在状态变化时需要通知所有观察者,可能会影响系统性能。可以通过合理设计来减少频繁通知的问题。
  2. 可能引起循环依赖:观察者模式可能导致循环依赖的问题。如果观察者之间相互依赖,可能会导致循环调用,增加调试和维护的难度。需小心设计避免这种情况发生。
  3. 可能引起内存泄漏:如果观察者没有被正确地移除或处理,可能会导致内存泄漏问题。当观察者长时间存在,而不再需要时,如果没有正确地解除订阅关系,可能会造成内存泄漏。

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

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

相关文章

内存问题检测

内存检测方式 gcc/g 内存检测方式如下,添加一些编译标签: -fsanitizeleak 检测内存泄漏。例如添加标签:-fsanitizeleak -g -O0-fsanitizeaddress 检测内存越界。例如添加标签:-fsanitizeaddress -g -O2,优化级别开…

ThreadLocal详解及ThreadLocal源码分析

提示:ThreadLocal详解、ThreadLocal与synchronized的区别、ThreadLocal的优势、ThreadLocal的内部结构、ThreadLocalMap源码分析、ThreadLocal导致内存泄漏的原因、要避免内存泄漏可以用哪些方式、ThreadLocal怎么解决Hash冲突问题、避免共享的设计模式、ThreadLoca…

Android DexOpt七种触发流程解析【原创硬核】

Android 13 DexOpt七种触发流程解析 众所周知,DexOpt是安卓应用性能优化非常重要的手段,相当于将应用对虚拟机的多层调用直接转化成了arm机器码。Dex优化过和没优化过,效果千差万别。本文深入解析android系统DexOpt机制的触发流程。 1 DexOpt…

如何学习自动化测试工具!

要学习和掌握自动化测试工具的使用方法,可以按照以下步骤进行: 一、明确学习目标 首先,需要明确你想要学习哪种自动化测试工具。自动化测试工具种类繁多,包括但不限于Selenium、Appium、JMeter、Postman、Robot Framework等&…

安全编程的代码示例

一、python代码示例 一个安全编程的示例是对输入进行严格的验证和过滤。比如,当用户在网页上输入用户名和密码时,应该对这些输入进行验证,防止恶意用户输入恶意代码或进行 SQL 注入等攻击。下面是一个简单的示例代码: import…

OpenFeign微服务调用组件

一、跨服务、跨进程调用方式 1)Httpclient 使用Httpclient我们首先需要引入依赖 <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.13</version> </depend…

Meta/东京电子/FPT软件等共同贡献,Aitomatic发布首个半导体行业开源大模型,「锁死」企业技术自主权

2024 年初&#xff0c;研究机构 Market.us 发布报告预测&#xff0c;全球半导体市场规模将大幅增长&#xff0c;预计 2024 年可达到 6,731 亿美元&#xff0c;到 2032 年预计将增长至 1.3 万亿美元。 毫无疑问&#xff0c;这个万亿级市场与充满想象空间的 AI 密不可分。技术层…

【根号分治】 通知

通知 分析&#xff1a; 这道题根号分治看起来就没有前面几题那么明显了 emm当然也可能是我境界还没到 我们考虑如果暴力修改&#xff0c;复杂度是 O ( n m ) O(nm) O(nm)&#xff0c;其实m为这个点的度数 考虑根号分治的思想&#xff0c;我们令 m M m\sqrt M mM ​ 并命度数大…

申瓯通信设备有限公司在线录音管理系统(复现过程)

漏洞简介 申瓯通信设备有限公司在线录音管理系统 index.php接口处存在任意文件读取漏洞&#xff0c;恶意攻击者可能利用该漏洞读取服务器上的敏感文件&#xff0c;例如客户记录、财务数据或源代码&#xff0c;导致数据泄露 一.复现过程 fofa搜索语句:title"在线录音管…

idea显示properties文件中文乱码的解决方法

1.如下 File-》Settings-》File Encodings,修改如下图中绿框标注的内容 2.点击Apply-->OK 3.修改完成后显示

ROS八股

目录 一、ros1和ros2的区别是什么&#xff1f; 二、rostopic 和 rosserver的区别是什么&#xff1f; 三、讲一下ros的navigation框架 一、ros1和ros2的区别是什么&#xff1f; ROS 1和ROS 2是两个主要版本的机器人操作系统&#xff0c;它们在多个方面存在显著差异&#xff…

【Stable Diffusion】(基础篇七)—— lora

lora 本系列博客笔记主要参考B站nenly同学的视频教程&#xff0c;传送门&#xff1a;B站第一套系统的AI绘画课&#xff01;零基础学会Stable Diffusion&#xff0c;这绝对是你看过的最容易上手的AI绘画教程 | SD WebUI 保姆级攻略_哔哩哔哩_bilibili 除了大模型和VAE之外&…

MySQL:集合运算符

集合运算符 MySQL中的 集合运算符&#xff08;Set operators&#xff09;主要用于结合两个或多个SELECT语句的结果集&#xff0c;这些结果集应该具有相同的列数和数据类型&#xff0c;以便能够进行比较或合并。 需要注意的是&#xff0c;MySQL本身并没有直接称为“Set operat…

Flask目录结构路由重定向简单实例讲解——轻量级的 Python Web 框架

假设一个flask目录结构如下&#xff1a; my_flask_app/ │ ├── app.py ├── routes/ │ ├── __init__.py │ ├── ZhejiangProvince/ │ │ ├── __init__.py │ │ ├── la.py │ │ └── el.py │ ├── GuangdongProvince/ │ │ ├…

常见服务限流方法

一、令牌桶算法&#xff08;Token Bucket&#xff09; 原理其实很简单&#xff0c;就是设置同一时刻服务器能处理请求的最大数量&#xff0c;如果超过这个数据&#xff0c;则需要等待&#xff0c;或者不处理请求。相当于设置最大并发量&#xff0c;但是细节是&#xff0c;还设…

解决nginx端口转发后,获取不到真实IP问题

文章目录 1&#xff0c;设置nginx端口转发1.2&#xff0c;无法获取客户端真实IP 2&#xff0c;nginx配置文件增加配置&#xff0c;保留客户端信息2.2&#xff0c;可以看到真实IP信息 1&#xff0c;设置nginx端口转发 location /AWAPI/ {proxy_pass http://172.28.43.19:9607; …

组件化开发

1.组件化开发 组件化&#xff1a;一个页面可以拆分成一个个组件&#xff0c;每个组件有着自己独立的结构[html]、样式[css]、行为 [js]。好处&#xff1a;便于维护&#xff0c;利于复用 → 提升开发效率。组件分类&#xff1a;普通组件、根组件。比如&#xff1a;下面这个页面…

二级MySQL(十二)——分组聚合查询

首先整理常用的聚合函数&#xff1a; 函数名说明COUNT&#xff08;*&#xff09;记录数COUNT&#xff08;列名&#xff09;一列的记录数MAX&#xff08;列名&#xff09;一列的最大值 MIN&#xff08;列名&#xff09; 一列的最小值 SUM&#xff08;列名&#xff09;一列…

M12电连接器航插插座L-code

M12电连接器概述 M12电连接器是一种广泛应用于工业自动化、传感器、仪器仪表、数据通信和控制系统等领域的圆形连接器。它的核心特点在于其小巧的尺寸、强大的多信号传输能力和出色的防水性能&#xff0c;使其成为众多工业应用的首选。M12连接器通常具有3至12个引脚&#xff0…