观察者模式

210 阅读3分钟

观察者模式由两类对象组成:主体和观察者。主体负责发布事件,同时观察者通过订阅这些事件来 观察该主体。该模式的一个关键概念是主体并不知道观察者的任何事情,也就是说它可以独自存在并正 常运作即使观察者不存在。从另一方面来说,观察者知道主体并能注册事件的回调函数(事件处理程序)。
下面写一下主题的代码:

function EventTarget () {
  this.handles = {}
}
EventTarget.prototype = {
  constructor: EventTarget ,
  addHandler: function(type, handler){
    if (typeof this.handles[type] == 'undefined') {
      this.handles[type] = []
    }
    this.handles[type].push(handler)
  },
  fire: function (event) {
    if(!event.target){
      event.target = this
    }
    if(this.handles[event.type] instanceof Array){
      var handlers = this.handles[event.type]
      for (var i = 0; i < handlers.length; i++) {
        handlers[i](event)
      }
    }
  },
  removeHandler: function (type, handler) {
    if(this.handles[type] instanceof Array){
      var handlers = this.handles[type]
      for (var i = 0; i < handlers.length; i++) {
        if (handlers[i] === handler) {
          break
        }
      }
      handlers.splice(i,1)
    }
  }
}

EventTarget 类型有一个单独的属性
handlers,用于储存事件处理程序。
还有三个方法:

  • addHandler(),用于注册给定类型事件的事件处理程序;
  • fire(),用于触发一个事件;
  • removeHandler(),用于注销某个事件类型的事件处理程序。

addHandler()方法接受两个参数:事件类型和用于处理该事件的函数。当调用该方法时,会进行 一次检查,看看 handlers 属性中是否已经存在一个针对该事件类型的数组;如果没有,则创建一个新 的。然后使用 push()将该处理程序添加到数组的末尾。

如果要触发一个事件,要调用 fire()函数。该方法接受一个单独的参数,是一个至少包含 type 属性的对象。fire()方法先给 event 对象设置一个 target 属性,如果它尚未被指定的话。然后它就 查找对应该事件类型的一组处理程序,调用各个函数,并给出 event 对象。因为这些都是自定义事件, 所以 event 对象上还需要的额外信息由你自己决定。

removeHandler()方法是 addHandler()的辅助,它们接受的参数一样:事件的类型和事件处理 程序。这个方法搜索事件处理程序的数组找到要删除的处理程序的位置。如果找到了,则使用 break 操作符退出 for 循环。然后使用 splice()方法将该项目从数组中删除。

观察者和观察者订阅事件的代码:(使用 EventTarget 类型的自定义事件)

function handleMessage (event) {
  console.log('Message received: '+ event.message)
}
var target = new EventTarget()
target.addHandler('message',handleMessage)
target.fire({type: 'message', message: 'hello World'})
target.removeHandler('message', handleMessage)
target.fire({type: 'message', message: 'hello World'})

在这段代码中,定义了 handleMessage()函数用于处理 message 事件。它接受 event 对象并输 出 message 属性。调用 target 对象的 addHandler()方法并传给"message"以及 handleMessage() 函数。在接下来的一行上,调用了 fire()函数,并传递了包含 2 个属性,即 type 和 message 的对象 直接量。它会调用 message 事件的事件处理程序,这样就会显示一个警告框(来自 handleMessage())。 然后删除了事件处理程序,这样即使事件再次触发,也不会显示任何警告框。