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

前提

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

观察者模式

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

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

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

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

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

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

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

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

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

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

  • 目标对象 Subject:

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

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

定义

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

javascript 复制代码
// 主题(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 收到到货通知,可以去购买手机了

图解结构

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

优点和缺点

优点:

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

缺点:

  1. 可能引起性能问题:如果通知过于频繁,观察者模式可能导致性能问题。当主题对象有大量观察者时,在状态变化时需要通知所有观察者,可能会影响系统性能。可以通过合理设计来减少频繁通知的问题。
  2. 可能引起循环依赖:观察者模式可能导致循环依赖的问题。如果观察者之间相互依赖,可能会导致循环调用,增加调试和维护的难度。需小心设计避免这种情况发生。
  3. 可能引起内存泄漏:如果观察者没有被正确地移除或处理,可能会导致内存泄漏问题。当观察者长时间存在,而不再需要时,如果没有正确地解除订阅关系,可能会造成内存泄漏。
相关推荐
小白学前端66614 分钟前
React Router 深入指南:从入门到进阶
前端·react.js·react
web1309332039834 分钟前
前端下载后端文件流,文件可以下载,但是打不开,显示“文件已损坏”的问题分析与解决方案
前端
outstanding木槿1 小时前
react+antd的Table组件编辑单元格
前端·javascript·react.js·前端框架
好名字08211 小时前
前端取Content-Disposition中的filename字段与解码(vue)
前端·javascript·vue.js·前端框架
隐形喷火龙2 小时前
element ui--下拉根据拼音首字母过滤
前端·vue.js·ui
m0_748241122 小时前
Selenium之Web元素定位
前端·selenium·测试工具
风无雨2 小时前
react杂乱笔记(一)
前端·笔记·react.js
前端小魔女2 小时前
2024-我赚到自媒体第一桶金
前端·rust
鑫~阳2 小时前
快速建站(网站如何在自己的电脑里跑起来) 详细步骤 一
前端·内容管理系统cms
egekm_sefg2 小时前
webrtc学习----前端推流拉流,局域网socket版,一对多
前端·学习·webrtc