侧边栏壁纸
博主头像
小白博主等级

just do it!

  • 累计撰写 60 篇文章
  • 累计创建 77 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

设计模式之发布订阅者模式

小白
2021-11-08 / 0 评论 / 0 点赞 / 97 阅读 / 782 字

描述

一个对象的某个状态改变时,订阅了这个对象的其他对象都将收到改对象状态改变的通知。

角色:发布者、订阅者、调度中心(处理中心)

  • 发布者(publisher),发布事件到订阅中心,使得调度中心通知订阅了该对象的所有订阅者(subscriber);
  • 订阅者(subscriber),把自己关注的发布者注册到调度中心,使得订阅的发布者发布事件是,调度中心能够通知到自己
  • 调度中心,统一管理发布者订阅者之间的关系,当发布者发布事件时,通知订阅此发布者消息的所有订阅者;实现发布者订阅者之间的解耦。

JavaScript实现发布订阅模式

class Event {
  constructor () {}
  // 调度中心:首先定义一个事件容器,用来装事件数组(因为订阅者可以是多个)
  handlers = {};

  // 订阅者向调度中心订阅方法:
  addEventListener(type:any, handler:any) {
    // 首先判断handlers内有没有type事件容器,没有则创建一个新数组容器
    if (!(type in this.handlers)) {
      this.handlers[type] = []
    }
    // 将事件存入
    this.handlers[type].push(handler)
  }

//修改调度中心中发布者下订阅者列表为指定的单个
  changeSingleEventListener(type:any, handler:any){
    if (!(type in this.handlers)) {
      this.handlers[type] = []
    }
    this.handlers[type]= [handler];
  }

  // 发布者向调度中心发布消息:触发事件两个参数(事件名,参数)
  // @ts-ignore
  dispatchEvent(type:any, ...params:any[]) {
    // 若没有注册该事件则抛出错误
    if (!(type in this.handlers)) {
      return new Error('未注册该事件')
    }
    // 便利触发
    this.handlers[type].forEach((handler:any) => {
      handler(...params)
    })
  }

  // 向调度中心移除订阅者方法:事件移除参数(事件名,删除的事件,若无第二个参数则删除该事件的订阅和发布)
  // @ts-ignore
  removeEventListener(type:any, handler:any) {
    // 无效事件抛出
    if (!(type in this.handlers)) {
      return new Error('无效事件')
    }
    if (!handler) {
      // 直接移除事件
      delete this.handlers[type]
    } else {
      const idx = this.handlers[type].findIndex((ele:any) => ele === handler);
      // 抛出异常事件
      if (idx === undefined) {
        return new Error('无该绑定事件')
      }
      // 移除事件
      this.handlers[type].splice(idx, 1)
      if (this.handlers[type].length === 0) {
        delete this.handlers[type]
      }
    }
  }
}
// @ts-ignore
// js引入及创建调度中心对象
let event = new Event();

向外抛出调度对象中处理发布者、订阅者之间的方法
export const addEventListener = (type: any, handler: any) => event.addEventListener(type, handler);
export const changeSingleEventListener = (type: any, handler: any) => event.changeSingleEventListener(type, handler);
export const removeEventListener = (type:any, handler:any) => event.removeEventListener(type, handler);
export const dispatchEvent = (type:any, ...params:any) => event.dispatchEvent(type, ...params);

简易版本:

调度中心

let callbacks = new Map();
const on = (topic, callback) => {
if (typeof callback !== 'function') return;
callbacks.set(topic, callback)
};
const off = topic=> {
callbacks.has(topic) && callbacks.delete(topic);
};
const emit = (topic, data) => {
if (callbacks.has(topic)) {
const callback = callbacks.get(topic);
typeof callback === 'function'&&callback(data);
}
};
module.exports = {
on:on,
off:off,
emit:emit
};

订阅者使用

const subscription = require("subscription.js");
subscription.on("topic name",()=>{})

发布者使用

const subscription = require("subscription.js");
subscription.emit("topic name",{})
0

评论区