5分钟从0到1实现一个订阅-发布模式

订阅-发布模式是设计模式中的一种应用场景比较多的模式,定义了一种对象间一对N的依赖关系(注意是一对N),当一个对象的状态发生改变时,全部依赖于它的对象都将获得更新。


订阅发布模式相较于观察者模式能够说是一种改进,其比观察者模式耦合性低。javascript

观察上图能够看到订阅发布模式大体能够分为三个角色,分别为发布者、管理中心(姑且这么称呼)、订阅者。管理中心就像一个中转站,维系着订阅者和发布者之间的关系,中转着各类不一样发布者发布的信息,并将其准确无误的派发到每种订阅者手中,有点儿像快递小哥儿哈(更像快递柜...)java

下面来说如何用js实现一个简单的订阅发布模式

首先咱们要设想下管理中心的功能:设计模式

  1. 与发布者和订阅者创建链接
  2. 当发布者要发布某些内容的时候及时派发给订阅者
  3. 当发布者不想跟管理中心合做了,双方要友好结束合做关系

有了功能咱们就要开始设想如何实现了,这里咱们假设每一个发布者只有发布一种消息,首先在有发布者A,发布者B,发布者C...的状况下就须要进行身份(key)辨认了,咱们先设置一个处理队列,分别存放每一个发布者要发布的信息。数组

let queue = {
  '发布者A的key': [
    function 订阅者a要这么作(){},
    function 订阅者b要这么作(){}
  ]
}复制代码

而后咱们已经存储了发布者A和订阅者a、b之间的关系了,下面咱们还要让A发布的时候分别执行a、b的订阅方法。因此基本代码为:函数

const bus = function (){
  let queue = {}, emit, on, off
  on = (key, fn) =>{
    if(!queue[key]){
      queue[key] = []
    }
    queue[key].push(fn)
  }
  emit = (key, ...args) => {
    let fns = queue[key]
    if(!fns || !fns.length){
      return
    }
    fns.map(_ => {
      _(...args)    })
  }
  return {
    $on: on,
    $emit: emit
  }
}复制代码

稍微解释下:$on方法即为收集依赖的方法,经过其能够将发布者与订阅者们的关系放处处理队列中,而后$emit方法为发布者发布更新的方法,当发布者发布更新的时候,对应key的函数组便会依次执行达到更新每一个订阅者的目的。ui

上述代码已经基本实现了功能,美中不足就是不能将发布者和订阅者“分手”,有合必有分,因此咱们还须要一个分手的方法。

大致思路:订阅者经过发布者的key来找到拟分手的发布者,而后提供本身的处理方法名字,而后在处理队列中删除,两不相欠,若是发布者想彻底退出还要把此key对应的处理方法都清空。spa

完整代码:设计

// 这里的bus就是一个管理中心,全部订阅者发布者能够经过其进行交流
const bus = ()=> {
  let queue = {}, emit, on, off
  on = (key, fn) =>{
    if(!queue[key]){
      queue[key] = []
    }
    queue[key].push(fn)
  }
  emit = (key, ...args) => {
    let fns = queue[key]
    if(!fns || !fns.length){ 
     return
    }
    fns.map(_ => {
      _(...args)
    })
  }
  off = (key, fn) => {
    if(queue[key] === undefined || queue[key].length === 0){
      return
    }
    if(fn !== undefined){
      queue[key] = queue[key].filter(_ => _ !== fn)
    } else{
      queue[key] = []
    }
  }
  return {
    $on: on,
    $emit: emit,
    $off: off
  }
}复制代码

好了,这就是订阅发布模式的简易实现,有兴趣的小伙伴能够在控制台试下如下代码~code

let bu = new bus()
function fn1(val){
  console.log(`fn1: ${val}`)
}
function fn2(val){
  console.log(`fn2: ${val}`)
}
function fn3(val){
  console.log(`fn3: ${val}`)
}
// 第一个监听
bu.$on('test', fn1)
// 第二个监听
bu.$on('test', fn2)
// 发布消息
bu.$emit('test', 'blablabla')
// 解绑第一个
bu.$off('test', fn1)
// 第三个监听
bu.$on('test', fn3)
// 发布消息
bu.$emit('test', 'hahaha')
// 所有解绑
bu.$off('test')
// 发布消息
bu.$emit('test', '???')复制代码


若有错误,还望你们指出,谢谢🙏cdn

相关文章
相关标签/搜索