JS每日一题:设计模式-如何理解观察者(发布订阅)模式?
发布于 12天前 作者 ab8512 270 次浏览 来自 分享
粉丝福利 : 关注VUE中文社区公众号,回复视频领取粉丝福利

20190411期

设计模式-如何理解观察者(发布订阅)模式?

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

生活实例理解:你今天去看一个楼盘,去了之后发布楼盘还没有对外销售,你不知道楼盘时候会对外销售,于是你找了楼盘的负责人,告诉他什么时候楼盘开始销售了电话通知你,然后想要买的人不是你一个,其它人也是通过留电话的方式给销售负责人来及时获取消息

不难发现,上面的例子正好对应上我们的观察者模式的定义, 多个想要买房的人同时订阅了一个主题(楼盘对外销售),这个主题更新时,这些观察者(买房)都会作出相应的动作

最熟悉的代码理解:

实际上,我们经常用到的事件绑定就是发布订阅模式

在这里我们想在用户点击的时候做出相应的处理,但是我们不知道用户在什么时候去点击,所以我们去订阅body上的click事件,在这里我们还可以去随意增加订阅者,这样并不影响我们的发布者

document.body.addEventListener('click',function(){
  console.log('JS 每日一题')
},false)

document.body.addEventListener('click',function(){
  console.log('今天你打卡了吗?')
},false)
实现一个简版的观察者

首先我们顺一下思路

  • 谁是发布者
  • 谁是订阅者
  • 发生改变时怎么通知订阅者作出相应动作
const Boss = {} //楼盘销售负责人
Boss.clientList = []; // 存放订阅者的回调
Boss.listen = function(fn){ // 增加订阅者
    this.clientList.push(fn); // 将买房人的号码缓存起来
}
Boss.trigger = function(){ // 发布消息
    for(var i=0,fn; fn= this.clientList[i++];){
      fn.apply(this,arguments)
    }
}

Boss.listen(function(msg){
  console.log(msg) // 开始销售了
})

cdBoss.trigger('开始销售了') // 发布消息

我们已经实现在最简易版的发布订阅,但其实是存在问题的,每个人可能订阅户型是不同的, 上面我们实现的是,只要一开始销售就通知所有订阅的人,显然是不合理的,我们将代码再来改写一下

// 订阅时给其加一个key做为标识,就相当于key就是订阅者的身份
Boss.listen = function(key, fn){
    if (!this.clientList[key]) {
      // 如果没有此类订阅,就给该类订阅增加一个缓存列表 
      this.clientList[key] = []
    }
    this.clientList[key].push(fn); 
}

Boss.trigger = function(){ // 发布消息
    const key = Array.prototype.shift.call(arguments),
    // 取出消息类型
    fns = this.clientList[key] 
    if (!fns || !fns.length) return // 如果该类消息没有订阅直接返回
    for (var i = 0, fn; fn = fns[i++]) {
        fn.apply(this, arguments)
    }
}

Boss.listen('老王', function (msg) {
  console.log('老王订阅户型' + cdName)
}) 
Boss.listen('老李', function (cdName) {
  console.log('老李订阅户型' + cdName)
}) 
Boss.trigger('老王', '143平米');
Boss.trigger('老李', '888平米');

好了,经过改写,消息只会推送给相关的订阅者了

总结

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

总的来说,观察者模式所做的工作就是在解耦,让耦合的双方都依赖于抽象,而不是依赖于具体。从而使得各自的变化都不会影响到另一边的变化

关于JS每日一题

JS每日一题可以看成是一个语音答题社区
每天利用碎片时间采用60秒内的语音形式来完成当天的考题
群主在次日0点推送当天的参考答案

  • 注 绝不仅限于完成当天任务,更多是查漏补缺,学习群内其它同学优秀的答题思路

点击加入答题

回到顶部