发布订阅模式 simple

/*
 * @Author: pengLei
 * @LastEditors: pengLei
 * @Date: 2021-12-14 14:08:01
 * @LastEditTime: 2021-12-14 16:09:03
 * @motto: Still water run deep
 * @Description: 发布者
 * @FilePath: \鱼泡PC网\src\dep\publish.ts
 */
// ! 重要方法,不容删除

/** 发布者 */
class Publish {
  name: string
  id: number
  messageMap: { [key: string]: {id: number; name: string; [x: string]: any}[] }
  /** name等同于给当前发布者一个名称 */
  constructor(name: string) {
    /** 消息事件订阅者集合对象 */
    this.messageMap = {}
    /** 随机id模拟唯一 */
    this.id = Date.now() + Math.ceil(Math.random() * 10000)
    this.name = name
  }

  /** 添加消息订阅者(subscriber等于订阅者) */
  addListener(subscriber: any, message: string) {
    if (!subscriber || !message) return false
    /** 如果消息列表不存在,就新建 */
    if (!this.messageMap[message]) {
      this.messageMap[message] = []
    }
    /** 比对ID查询!!! */
    const existIndex = this.messageMap[message].findIndex(exitSubscriber => exitSubscriber.id === subscriber.id)
    /** 不存在这个订阅者时添加 */
    if (existIndex === -1) {
      /** 吧订阅者装进去 */
      this.messageMap[message].push(subscriber)
    } else {
      /** 存在的时候呢 直接替换 */
      this.messageMap[message][existIndex] = subscriber
    }
  }

  /** 删除消息订阅者 */
  removeListener(subscriber: any, message: string) {
    if (!subscriber) return false

    /** 如果传了message只删除此message下的订阅关系,否则删除此订阅者的所有订阅关系 */
    const messages = message ? [message] : Object.keys(this.messageMap)
    /** 遍历Key */
    messages.forEach(_message => {
      const subscribers = this.messageMap[_message]
      if (!subscribers) return false

      let i = subscribers.length
      while (i--) {
        if (subscribers[i].id === subscriber.id) {
          subscribers.splice(i, 1)
        }
      }
      /** 数组元素如果没有了。直接吧订阅器删除 */
      if (!subscribers.length) delete this.messageMap[_message]
    })
  }
  
  /** 发布通知 */
  publish<D extends any>(message: string, info: D) {
    const subscribers = this.messageMap[message] || []
    let handlerKey = message + "_" + this.id + "_handler"
    /** 找出当前索引订阅者,依次发送通知 */
    subscribers.forEach(subscriber => {
      subscriber[handlerKey](subscriber, info)
    })
    return this
  }
}

export default Publish
/*
 * @Author: pengLei
 * @LastEditors: pengLei
 * @Date: 2021-12-14 14:03:52
 * @LastEditTime: 2021-12-14 16:08:15
 * @motto: Still water run deep
 * @Description: 订阅者
 * @FilePath: \鱼泡PC网\src\dep\subscribe.ts
 */
// ! 重要方法,不容删除

type listenType = {
  publisher: any,
  message: string,
  handler: (subscribe: {[x: string]: any}, info: any) => void
}

/** 订阅者 */
class Subscribe {
  id: number;
  name: string;
  [x: string]: any
  /** name等同于给当前订阅者一个名称 */
  constructor(name: string = 'subscriber') {
    this.name = name
    /** 随机id模拟唯一 */
    this.id = Date.now() + Math.ceil(Math.random() * 10000)
  }
  /** 
   *  订阅器
   *  @publisher 订阅的是哪个发布者(比如你订阅的是鱼泡发布者)
   *  @message 订阅的消息,(非常重要的字段)(比如你订阅的是鱼泡发的招工信息key。绑定关系)
   *  @handler 收到消息后的处理方法
   */
  listen({publisher, message, handler}: listenType) {
    /** 订阅消息的回调函数 */
    if (publisher) {
      /** 一个订阅者可以同时订阅多个发布者,所以回调函数要拼接上对应发布者的id */
      this[message + '_' + publisher.id + "_handler"] = handler
      publisher.addListener(this, message)
    }
    /** 链式 */
    return this
  }
  /** 取消订阅 */
  unlisten(publisher: any, message: string) {
    if (publisher) {
      publisher.removeListener(this, message)
    }
    /** 链式 */
    return this
  }
}

export default Subscribe

/*
 * @Author: pengLei
 * @LastEditors: pengLei
 * @Date: 2021-12-14 15:34:28
 * @LastEditTime: 2021-12-14 16:06:22
 * @motto: Still water run deep
 * @Description: 订阅器(采集所有需要订阅的实例)
 * @FilePath: \鱼泡PC网\src\dep\listener.ts
 */
import {Subscribe, Publish} from "."

/** 示例 (可以链式,多绑定)说白了就是一个人可以绑定A的发布者,也可以绑定B的发布者,还可以绑定A的发布其他信息
 *  LoginSubscribe.listen({
        publisher: APublish, // 绑定发布者是A
        message: '找活', // 绑定发布者是发布的找活
        handler: (self, info) => {
          console.log(self, dispatch)
        }
      }).listen({
        publisher: BPublish,
        message: '招工',
        handler: (self, info) => {
          consol.log(info == '我要找一个工人啦')
          console.log(self, dispatch)
        }
      })
    
    BPublish.publish('招工', '我要找一个工人啦!')

    如不多个人绑定了B的招工,那么B发布者一旦放送信息,全体订阅者会收到信息
 */

/** 登录的发布者 */
const LoginPublish = new Publish('LoginPublish')
/** 登录的订阅者 */
const LoginSubscribe = new Subscribe('LoginSubscribe')

/** 你可以在这里处理更多的发布订阅 */
// ....

export {
  LoginPublish,
  LoginSubscribe
}
原文地址:https://www.cnblogs.com/plBlog/p/15688470.html