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

前提

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

观察者模式

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

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

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

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

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

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

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

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

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

在观察者模式中,只有两种主体:目标对象 (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. 可能引起内存泄漏:如果观察者没有被正确地移除或处理,可能会导致内存泄漏问题。当观察者长时间存在,而不再需要时,如果没有正确地解除订阅关系,可能会造成内存泄漏。
相关推荐
神夜大侠19 分钟前
VUE 实现公告无缝循环滚动
前端·javascript·vue.js
明辉光焱21 分钟前
【Electron】Electron Forge如何支持Element plus?
前端·javascript·vue.js·electron·node.js
柯南二号1 小时前
HarmonyOS ArkTS 下拉列表组件
前端·javascript·数据库·harmonyos·arkts
wyy72931 小时前
v-html 富文本中图片使用element-ui image-viewer组件实现预览,并且阻止滚动条
前端·ui·html
前端郭德纲1 小时前
ES6的Iterator 和 for...of 循环
前端·ecmascript·es6
王解1 小时前
【模块化大作战】Webpack如何搞定CommonJS与ES6混战(3)
前端·webpack·es6
欲游山河十万里1 小时前
(02)ES6教程——Map、Set、Reflect、Proxy、字符串、数值、对象、数组、函数
前端·ecmascript·es6
明辉光焱1 小时前
【ES6】ES6中,如何实现桥接模式?
前端·javascript·es6·桥接模式
PyAIGCMaster2 小时前
python环境中,敏感数据的存储与读取问题解决方案
服务器·前端·python
baozhengw2 小时前
UniAPP快速入门教程(一)
前端·uni-app