观察者模式

72 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第27天,点击查看活动详情

导言

观察者模式又叫发布—订阅模式,当对象间存在一种一对多的依赖关系,其中一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。这样就避免了依赖对象不断的去向被依赖对象进行轮询查询自己想要的信息。

观察者模式还是经常用到的,拿买股票来举个例子:我们有时候看中一只股票的时候,想在某个心理价位去购买它,但盘面是实时变化的,这样就不得不让我们实时盯盘,浪费很多的精力。为了解决这个问题,现在炒股应用都可以设置买入价格,到时候自动帮你买入,或者符合了你订阅的条件就会通知你。这就是观察者模式,其实很好理解。

观察者模式

对于观察者模式,我们再用代码来说明:

// event对象定义:发布-订阅功能
let event = {
  clientList: [],
  listen: function (key, fn) {
    if (!this.clientList[key]) {
      this.clientList[key] = []
    }
    this.clientList[key].push(fn)
  },
  trigger: function () {
    let key = Array.prototype.shift.call(arguments)
    let fns = this.clientList[key]
    if (!fns || fns.length === 0) {
      return false // 没有订阅
    }
    for (let i = 0; i< fns.length; i++) {
      fns[i].apply(this, arguments)
    }
  }
}
// 给所有对象都动态安装发布-订阅功能
let installEvent = function (obj) {
  for (let i in event) {
    obj[i] = event[i]
  }
}

//  执行发布-订阅功能
let sales = {}
installEvent(sales)
sales.listen('mac20000', function (price) {
  console.log('价格:' + price)
})
sales.listen('iphone1000', function (price) {
  console.log('价格:' + price)
})

sales.trigger('mac20000', 20000) // '价格:20000'
sales.trigger('iphone1000', 10000) // '价格:10000'

我们先定义了event对象来实现发布-订阅功能,installEvent来给所有需要的对象来安装。再定义一个sales销售对象,安装后,进行监听商品的价格。当商品价格达到客户的订阅价格,就会执行trigger方法来通知客户。

除了客户和商家间的这种关系,其实在开发过程中,发请求后,等待接口返回也是一种观察者模式,接口完成数据的处理后,就会通知客户端来及时获取执行的结果,成功或者失败。

优点

  • 时间上的解耦
  • 对象之间的解耦

不足

创建订阅者本身要消耗一定的时间和内存,当你订阅一个消息后,如果消息最后都未发生,但这个订阅者会始终存在于内存中。

观察者模式虽然可以弱化对象之间的联系,但如果过度使用,对象间的必要联系也将被深埋在背后,会导致我们程序难以跟踪维护和理解。特别是有多个发布者和订阅者嵌套到一起的时候,要跟踪一个bug就比较困难,也要慎用。