浅谈发布订阅模式与观察者模式

设计模式并非是软件开发的专业术语,实际上,“模式”最早诞生于建筑学。

设计模式的定义是:在面向对象软件设计过程中针对特定问题的简洁而优雅的解决方案。通俗一点说,设计模式是在某种场合下对某个问题的一种解决方案。如果再通俗一点说,设计模式就是给面向对象软件开发中的一些好的设计取个名字。

这些“好的设计”并不是谁发明的,而是早已存在于软件开发中。一个稍有经验的程序员也许在不知不觉中数次使用过这些设计模式。GoF(Gang of Four--四人组,《设计模式》几位作者)最大的功绩是把这些“好的设计”从浩瀚的面向对象世界中挑选出来,并且给予它们一个好听又好记的名字。

设计模式并不直接用来完成代码的编写,而是描述在各种不同情况下,要怎么解决问题的一种方案,他不是一个死的机制,他是一种思想,一种写代码的形式。每种语言对于各种设计模式都有他们自己的实现方式,对于某些设计模式来说,可能在某些语言下并不适用,比如工厂方法模式对于javascript。模式应该用在正确的地方。而哪些才算正确的地方,只有在我们深刻理解了模式的意图之后,再结合项目的实际场景才会知道。。

模式的社区一直在发展。GoF在1995年提出了23种设计模式,但模式不仅仅局限于这23种,后面增加到了24种。在这20多年的时间里,也许有更多的模式已经被人发现并总结了出来,比如一些JavaScript 图书中会提到模块模式、沙箱模式等。这些“模式”能否被世人公认并流传下来,还有待时间验证。

观察者模式(Observer Pattern)

观察者模式定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知,并自动更新。观察者模式属于行为型模式,行为型模式关注的是对象之间的通讯,观察者模式就是观察者和被观察者之间的通讯。

观察者模式有一个别名叫“发布-订阅模式”,或者说是“订阅-发布模式”,订阅者和订阅目标是联系在一起的,当订阅目标发生改变时,逐个通知订阅者。我们可以用报纸期刊的订阅来形象的说明,当你订阅了一份报纸,每天都会有一份最新的报纸送到你手上,有多少人订阅报纸,报社就会发多少份报纸,报社和订报纸的客户就是上面文章开头所说的“一对多”的依赖关系。

发布订阅模式(Pub-Sub Pattern)

其实24种基本的设计模式中并没有发布订阅模式,上面也说了,他只是观察者模式的一个别称。

但是经过时间的沉淀,似乎他已经强大了起来,已经独立于观察者模式,成为另外一种不同的设计模式。

在现在的发布订阅模式中,称为发布者的消息发送者不会将消息直接发送给订阅者,这意味着发布者和订阅者不知道彼此的存在。在发布者和订阅者之间存在第三个组件,称为消息代理或调度中心或中间件,它维持着发布者和订阅者之间的联系,过滤所有发布者传入的消息并相应地分发它们给订阅者。

举一个例子,你在微博上关注了A,同时其他很多人也关注了A,那么当A发布动态的时候,微博就会为你们推送这条动态。A就是发布者,你是订阅者,微博就是调度中心,你和A是没有直接的消息往来的,全是通过微博来协调的(你的关注,A的发布动态)。

观察者模式和发布订阅模式有什么区别?

我们先来看下这两个模式的实现结构:

浅谈发布订阅模式与观察者模式

观察者模式:观察者(Observer)直接订阅(Subscribe)主题(Subject),而当主题被激活的时候,会触发(Fire Event)观察者里的事件。

发布订阅模式:订阅者(Subscriber)把自己想订阅的事件注册(Subscribe)到调度中心(Topic),当发布者(Publisher)发布该事件(Publish topic)到调度中心,也就是该事件触发时,由调度中心统一调度(Fire Event)订阅者注册到调度中心的处理代码。

我们再来看下这两个模式的代码案例:(猎人发布与订阅任务)

观察者模式:

//有一家猎人工会,其中每个猎人都具有发布任务(publish),订阅任务(subscribe)的功能 //他们都有一个订阅列表来记录谁订阅了自己 //定义一个猎人类 //包括姓名,级别,订阅列表 function Hunter(name, level){ this.name = name this.level = level this.list = [] } Hunter.prototype.publish = function (money){ console.log(this.level + '猎人' + this.name + '寻求帮助') this.list.forEach(function(item, index){ item(money) }) } Hunter.prototype.subscribe = function (targrt, fn){ console.log(this.level + '猎人' + this.name + '订阅了' + targrt.name) targrt.list.push(fn) } //猎人工会走来了几个猎人 let hunterMing = new Hunter('小明', '黄金') let hunterJin = new Hunter('小金', '白银') let hunterZhang = new Hunter('小张', '黄金') let hunterPeter = new Hunter('Peter', '青铜') //Peter等级较低,可能需要帮助,所以小明,小金,小张都订阅了Peter hunterMing.subscribe(hunterPeter, function(money){ console.log('小明表示:' + (money > 200 ? '' : '暂时很忙,不能') + '给予帮助') }) hunterJin.subscribe(hunterPeter, function(){ console.log('小金表示:给予帮助') }) hunterZhang.subscribe(hunterPeter, function(){ console.log('小张表示:给予帮助') }) //Peter遇到困难,赏金198寻求帮助 hunterPeter.publish(198) //猎人们(观察者)关联他们感兴趣的猎人(目标对象),如Peter,当Peter有困难时,会自动通知给他们(观察者)

发布订阅模式:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/ae9c28e25a1bb6df0d3678f12498889d.html