『面试的底气』—— 设计模式之发布-订阅模式(一)

1,467 阅读4分钟

定义

发布-订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。在 JavaScript 开发中,我们一般用事件模型来替代传统的发布—订阅模式。

理解

用一个生活中的例子来生动介绍一下发布-订阅模式。

小王最近看上一款手机,而这款手机只有在线下体验店才有卖,于是小王跑到线上体验店去购买时,销售员小敏告诉小王,这款手机昨天已经卖完了。但是店长已经去进货了,然后什么时候能进到货就不太清楚了。最后小王记下售货员小敏的电话就离开了。

在随后的日子中,小王每天都会打电话给小敏,咨询手机到货了没有。然后除了小王,还是小林、小李、小赵等等也会打电话给小敏,咨询手机到货了没。就这样过了一个礼拜,小敏辞职了,为啥呢?因为每天都忙着接电话,都没有空卖其他手机,没有业绩赚不到钱。

当然现实中没傻的销售员,一般销售员只会告诉顾客,如何你想购买的话,留下你的电话号码,手机一到货就马上通知你。于是小王、小林、小李、小赵的名字和电话号码都被销售员记在体验店中一个本子上,,当手机到货时,销售员就会翻开本子,一个个发短信过来通知他们过来买手机。

作用

在上面的例子中,发送短信通知就是一个典型的发布-订阅模式。小王、小林、小李、小赵等购买者都是订阅者,他们订阅了手机到货的消息,体验店作为发布者,体验店中的销售员会在手机到货的时候遍历本子上记录的电话号码,依次给购买者发布消息(发送短信通知)。

我们在这个例子中可以使用发布—订阅模式有着显而易见的优点:

  • 购买者不用再天天给销售员打电话咨询手机到货时间,只要手机到货了,体验店作为发布者会通知这些消息订阅者。

  • 购买者和体验店之间不再强耦合在一起,当有新的购买者出现时,他只需把手机号码留在体验店中的本子上,体验店不关心的任何情况,不管购买者是男是女。 而体验店的任何变动也不会影响购买者,比如销售员离职,体验店搬到顶一个地方,这些改变都跟购买者无关,只要体验店记得发短信这件事情。

在这里可以大概明确发布-订阅模式的作用:

  • 发布—订阅模式可以广泛应用于异步编程中,这是一种替代传递回调函数的方案。在异步编程中使用发布—订阅模式,无需过多关注对象在异步运行期间的内部状态,只需要订阅想要获取的对象出现点即可。

  • 发布—订阅模式可以取代对象之间硬编码的通知机制,一个对象不用再显式地调用另外一个对象的某个接口。发布—订阅模式让两个对象松耦合地联系在一起,虽然不太清楚彼此的细节,但这不影响它们之间相互通信。当有新的订阅者出现时,发布者的代码不需要任何修改;同样发布者需要改变时,也不会影响到之前的订阅者。只要之前约定的事件名没有变化,就可以自由地改变它们。

JavaScript中的发布-订阅模式

在上面介绍一个生活中的发布-订阅模式,接下来介绍一个JavaScript中非常常见的发布-订阅模式,那就是在 DOM 节点上面绑定事件函数。

document.body.addEventListener('click', function () {
  console.log(1);
}, false);
document.body.click();

假如我们要监控用户点击document.body的动作,但是我们没办法预知用户将在什么时候点击。所以我们用addEventListener订阅document.body上的click事件,当 body 节点被点击时,body 节点便会向订阅 者发布这个消息。

当然我们还可以随意增加或者删除订阅者,增加任何订阅者都不会影响发布者代码的编写:

document.body.addEventListener('click', function () {
  console.log(1);
}, false);
document.body.addEventListener('click', function () {
  console.log(2);
}, false);
document.body.addEventListener('click', function () {
  console.log(3);
}, false);
document.body.click();

其中document.body.click()就是发布者,document.body.addEventListener('click',function () {},false) 就是订阅者,订阅者随便增加或删除,对于发布者没有任何影响。

小结

本文用一个买手机生活的例子来生动形象介绍了什么是发布-订阅模式,并从中提取出一些发布-订阅模式的优点和作用,最后介绍了一个JavaScript中一个现成的发布-订阅模式(节点绑定DOM事件),下篇文章将把买手机生活的例子实现成代码来介绍如何一步一步实现一个发布-订阅模式。