简单实现观察者模式和发布订阅模式

2,564 阅读2分钟

网上有很多这样的文章 但是看起来很枯燥 而且含糊 甚至模轮两可 今天谈谈我对观察者模式和发布订阅模式的理解

观察者模式

观察者模式指的是一个对象(Object a)维持一系列依赖(关注这个词感觉更好)它的对象(Object b,c,d) 当它的有关状态发生变化时Object a就要通知一系列Object b,c,d对象进行更新

在该模式下 Object a拥有添加,删除和通知一系列Object b,c,d对象的方法,而Object b,c,d拥有更新等方法

下面我们实现一个观察者模式

class Subject{
    constructor () {
      this.observers =[]
    }
    add (observer) {
      this.observers.push(observer)
    }
    remove (observer) {
      this.observers.map((item, index) => {
        if (item === observer) {
            this.observers.splice(index, 1)
        }
      })
    }
    notify () {
      this.observers.map((item, index) => {
          item.update()
      })
    }
}
class Observer {
    constructor (name) {
        this.name = name
    }
    update () {
        console.log("I`m " + this.name)
    }
}
var sub = new Subject()
var obs1 = new Observer("obs1")
var obs2  = new Observer("obs2")
sub.add(obs1)
sub.add(obs2)
sub.notify() // I`m obs1   I`m obs2
sub.remove(obs2)
sub.notify()  //I`m obs1

上述代码,我们创建了一个Subject对象和两个Observer对象 当相关信息发生变化 即通知变化 我们也可以移出相关依赖的对象

发布订阅模式

发布订阅模式指的是订阅者基于一个事件通过自定义事件订阅主题 被订阅者(发布者)通过发布主题事件方式通知订阅该主题的订阅者进行更新等操作

举个栗子

我喜欢看NBA 喜欢湖人队 (湖人总冠军) 我在新浪体育关注了湖人队 没关注🚀 那么只要湖人一有新消息就会通知我 🚀夺冠也不会推送消息给我

一般我们需要做埋点 这个时候就可以用到 只要我在这块埋点用的图片被请求 我就让你触发相应的事件

下面我们来看看具体代码

let event= {
    list:[],
    on (key, fn) {
      if  (!this.list[key]) {
          this.list[key] = []
      }
      this.list[key].push(fn)
    },
    emit () {
        let key = [].shift.call(arguments),
            fns = this.list[key]
        if (!fns || fns.length === 0 ) {
            return false
        }
        fns.forEach(element => {
           element.apply(this,arguments) 
        });
    },
    remove (key,fn) {
        let fns = this.list[key]
        if (!fns) return false
        if (!fn) {
            fns && (fns.length = 0)
        }else {
            fns.forEach((item,i) => {
                if(item === fn) {
                    fns.splice(i, 1)
                }
            })
        }
    }
}
function car () {
    console.log("我是劳斯莱斯幻影")
}
function rocket () {
    console.log("我是真理")
}
event.on('thing',data => {
    console.log("接收")
    console.log(data)
})
event.on('thing',car)
event.on('thing',rocket)
event.emit('thing',['宝马','奔驰'])

思路

  • 创建一个对象(缓存队列)
  • on方法把回调函数添加到缓存列表
  • emit方法取arguments里第一个作为key 根据key值去执行对应缓存队列中的函数
  • remove方法根据key取消订阅

总结

两者都是定义了一个一对多的依赖关系 当有关状态发生变化时执行相应的更新 本质上的思想都是一样的 而发布订阅可以看做是观察者的进阶版 设计模式是一种思想 具体的需求实现有不同的方式 使用也要基于不同的场景 各自把握