JavaScript发布订阅者模式

497 阅读2分钟

假如你要建立一个网站,通常来说会有许多用户。你作为一名管理者,有时候需要将重要的消息发布给你的用户。在软件开发领域,开发此功能往往用到发布订阅者模式。下面我以简单的javascript来说明。

  1. 定义发布者类。发布者最基本的两个属性:发送的消息,发送的人
function Publisher() {
  this.observers =[]; // 存储需要发布消息的人
  this.state="hello"  // 发送的消息
}

除此之外,一个Publisher还需要有能够接纳新的订阅消息的人的功能,或者删除某个订阅者的功能,同时需要能够将消息发送出去的功能。

// 新增订阅者功能
Publisher.prototype.addUser=function(obj) {
  const nameList= this.observers.map(item=>{
    return item.name;
  })
  if(nameList.indexOf(obj.name) < 0) {
    this.observers.push(obj)
  }
  return this;
}
//删除订阅者功能
Publisher.prototype.deleteUser=function(obj){
  let index = -1
  this.observers.forEach((item,key)=>{
    if(item.name === obj.name){
      index = key
    }
  })
  if(index !== -1) {
    this.observers.splice(index,1)
  }
  return this
}
// 通知订阅者功能
Publisher.prototype.noticeUser=function(data){ 
  this.observers.forEach((item)=>{
    item.update(data)
  })
}

值得注意的是,上述通知订阅者的功能是通过遍历this.observers 并调用每一个订阅者的update方法。所以每一个订阅者需要对应有update方法。每一个订阅者的类似结构如下:

[
  {
    name:'张三',
    update:(data)=>{console.log(data)}
  },
  {
    name:'李四',
    update:(data)=>{console.log(data)}
  },
  ...
]
  1. 构造订阅者对象,由于每一个订阅者都有name属性和update方法。最简单的就是采用构造函数方法来实现
function Subscribe(name){
  this.name =name;
  this.update = function(data){
    console.log(data);
  };
}
  1. 有了Subscribe模板,我们开始构造出每一个具体的订阅者实例出来。
let lisi = new Subscribe('lisi')
let xiaoming = new Subscribe('xiaoming')
  1. 将构造的订阅人lisi 和 xiaoming 加入到发布者对象的observer中
let pb = new Publisher()
pb.addUser(lisi)
pb.addUser(xiaoming)
  1. 发布者需要发布消息时:
pb.noticeUser("hello")

至此一个最简单的发布订阅者模式实现了,这里还有两点优化建议。
第一,上述构造出来的lisi,xiaoming都会自动有update方法,并且update的行为都是一样的,如果需要例如xiaoming的update与其他不同,只需要重新定义即可

xiaoling.update=(data)=>{console.log("hello"+data)}
pb.addUser(xiaoling)

第二, 发布者需要手动调用pb.noticeUser()去通知state消息,可以做到state变动了自动去调用pb.noticeUser()吗?可以的,此时 Object.defineProperty()就派上用场了

let pb = new Publisher()
Object.defineProperty(pb,'state',{
  set:function(newVal,) {
    let a = this
    debugger
    pb.noticeUser(newVal)   
  }
})
pb.addUser(lisi)
pb.addUser(xiaoming)
pb.state = '123'
//pb.noticeUser()

如果state变化了将自动触发pb.noticeUser(),实现自动通知功能,是不是有点Vue原理既视感!