今天我们讨论的是发布-观察者模式,也叫订阅模式,在javascript里,该模式要如何实现呢,首先我们先看一个现实生活中的例子

小明在工作几年后,准备买房结婚,于是他到售楼处,找售楼人员询问当前的价格,得知售楼价每平是小明好几个月工资的时候,小明犹豫了,于是他回去后,每天都给售楼处打电话,询问售楼人员的价格,售楼人员也会耐心解答,但是第二天又来了一个小芳,于是小芳每天也在打电话,时间久了,人越来越多,售楼人员每天接这么多电话,肯定吃不消要跳槽,当然我们只是举例子,现实情况是,售楼人员会留下小明,小芳等等人的电话存在花名册里,这就是订阅,然后等房价降下来的时候,售楼人员一个个打电话通知他们,这样双方都省了力气,订阅消息的人也拿到了应得的消息。现在假设花名册是 clientList <array>, 售楼处是salePart<object>,以此我们写一个简单发布-观察者模式的代码

var salePart = {}  // 售楼处
  var clientList = []  // 花名册

  var xiaoming = {
    name: '小明',
    fn: function () {
      var args = [].slice.call(arguments)
      args.unshift(this.name)
      console.log(args.join(','))
    }
  }

  salePart.listen = function (person) {  // 售楼处登记来访者的信息
    clientList.push(person)
  }

  salePart.trigger = function (type, price) {  // 售楼处通知来访者信息,type为售房面积,price为售房价格
    if (clientList.length > 0) {
      for (var i = 0, person; person = clientList[i++];) {
        if (typeof person.fn === 'function') {
          person.fn(type, price)
        }
      }
    }
  }

  salePart.listen(xiaoming)
  salePart.trigger('square80', 60000)  // 打印出来  小明,square80,60000

下面小芳也要来看房,可是小芳比小明有钱的多,她要看的是200平米的房子,这样把小芳在添加进去的时候,售楼处就不能按照分类来进行通知他们的,200平米的房子的通知小明也能看到,这样小明会更扎心,万一不开心,就会损失一个潜在客户,所以我们还要完善一下上述代码,让售楼处可以按照房屋面积分别通知对应的买房者

 var salePart = {}  // 售楼处
  var clientList = {}  // 花名册

  var xiaoming = {
    name: '小明',
    type: 's80',
    fn: function () {
      var args = [].slice.call(arguments)
      args.unshift(this.name)
      console.log(args.join(','))
    }
  }

  var xiaofang = {
    name: '小芳',
    type: 's200',
    fn: function () {
      var args = [].slice.call(arguments)
      args.unshift(this.name)
      console.log(args.join(','))
    }
  }

  salePart.listen = function (person) {  // 售楼处登记来访者的信息
    var type = person.type
    if (!clientList[type] || clientList[type].length < 0) {  // 原来的花名册先分类,然后再存入每个人的信息
      clientList[type] = []
    }
    clientList[type].push(person)
  }

  salePart.trigger = function (type, price) {  // 售楼处通知来访者信息,type为售房类型,price为售房价格
    if (clientList[type] && clientList[type].length > 0) {
      for (var i = 0, person; person = clientList[type][i++];) {
        if (typeof person.fn === 'function') {
          person.fn(type, price)
        }
      }
    }
  }

  salePart.listen(xiaoming)
  salePart.listen(xiaofang)

  salePart.trigger('s80', 60000)  // 打印出来  小明,square80,60000
  salePart.trigger('s200', 200000)  // 打印出来  小芳,square200,200000

可以看到,小明只能接收到80平米的房价信息,小芳呢,也只能看到200平米的房价信息,这样售楼处又回到了一片欣欣向荣的社会主义和谐景象,但是在实际开发中,上面的代码并不利于维护,因为很松散,我们可以用对象的方式来把代码重构一下

var SalePart = function () {
    this.clientList = {}
  }

  SalePart.prototype.listen = function () {  // 现在我们把该函数处理为可以一次接收多个来访者
    var persons = [].slice.call(arguments)

    for (var i = 0, p; p = persons[i++];) {
      var type = p.type
      if (!this.clientList[type] || this.clientList[type].length < 0) {
        this.clientList[type] = []
      }
      this.clientList[type].push(p)
    }
  }

  SalePart.prototype.trigger = function (type, price) {
    if (this.clientList[type] && this.clientList[type].length > 0) {
      for (var i = 0, p; p = this.clientList[type][i++];) {
        if (typeof p.fn === 'function') {
          p.fn(type, price)
        }
      }
    }
  }

  var salePart = new SalePart()
  salePart.listen(xiaoming, xiaofang)
  salePart.trigger('s80', 50000)  // 小明,s80,50000 感谢党和国家房价终于降了!
  salePart.trigger('s200', 100000)  // 小芳,s200,100000  这么便宜,买买买!!!

以上就是本章的内容,结合实际案例希望大家看起来更好理解一些,如有疑问,可以在下方留言,看到后我会尽快回复。


遠夏
4 声望0 粉丝