设计模式 - 观察者模式

观察者模式也叫发布订阅模式,Publish 发布 / Subscribe 订阅,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

举例

  1. 你的微信订阅了某个公众号,公众号某天发布了一篇文章,你的微信上就能收到消息并且查看这篇文章,不止是你能收到,其他人如果订阅了这个公众号也能收到。

  2. 基于 web 开发的事件绑定:click、mousemove、keydown、onload 等。

优点

  1. 支持简单的广播通信,自动通知所有已经订阅过的对象。
  2. 页面载入后目标对象很容易与观察者存在一种动态关联,增加了灵活性。
  3. 目标对象与观察者之间的抽象耦合关系能够单独扩展以及重用。

实现

window.onload = function () {
  var slice = Array.prototype.slice

  function Observer() {
    this.events = {}
  }

  Observer.prototype = {
    subscribe: function (signals, fn) {
      signals = signals.split(' ')
      signals.forEach((signal) => {
        if (!this.events[signal]) {
          this.events[signal] = []
        }
        fn && (this.events[signal].push(fn))
      })
    },
    publish: function (signals) {
      var args = slice.call(arguments, 1)
      signals = signals.split(' ')
      signals.forEach((signal) => {
        var events = this.events[signal]
        if (events) {
          events.forEach(function (fn) {
            fn.apply(this, args)
          })
        }
      })
    },
    unsubscribe: function (signal, fn) {
      var events = this.events[signal]
      if (events) {
        events.forEach((fn) => {
          events.splice(events.indexOf(fn), 1)
        })
      }
    }
  }

  // 创建
  var workday = new Observer()
  // 订阅
  var gowork = workday.subscribe('9点 10点', function (name) {
    console.log(name + '上班时间到啦。')
  })
  var offwork = workday.subscribe('17点 18点', function (name) {
    console.log(name + '下班时间到啦。')
  })
  var eat = workday.subscribe('19点', function (name) {
    console.log(name + '吃饭时间到啦。')
  })

  // 取消订阅
  workday.unsubscribe('19点', eat)
  // 发布订阅
  workday.publish('19点', 'Tony')

  var hours = new Date().getHours()

  if (hours > 9 && hours < 17) {
    workday.publish('9点', 'Tony')
  } else {
    workday.publish('17点', 'Tony')
  }
}