浅谈javascript设计模式之发布订阅者模式

蚊子前端博客
发布于 2017-09-15 10:22
发布订阅者模式是为了发布者和订阅者之间避免产生依赖关系,发布订阅者之间的订阅关系由一个中介列表来维护。发布者只需做好发布功能,至于订阅者是谁,订阅者做了什么事情,发布者是无需关心的

发布订阅者模式又称为观察者模式,有的书本中也对这两个模式进行了更加细致的区分!这里我们只研究发布订阅者模式。

1. 什么是发布订阅者模式

发布订阅者模式,我们可以通俗地用微信公众号来比喻:

  • 只有该公众号的订阅者才能收到推送

  • 公众号只负责推送信息,不关心是谁订阅了我,只要有信息推送,那么就推送给所有的订阅者

  • 订阅者无需时不时的查看公众号是否有信息推送,只要公众号推送信息后,该订阅者就会收到通知

  • 订阅者可随时取消对该公众号的订阅

从这个比喻来看,发布订阅者模式是为了发布者和订阅者之间避免产生依赖关系,发布订阅者之间的订阅关系由一个中介列表来维护。发布者只需做好发布功能,至于订阅者是谁,订阅者做了什么事情,发布者是无需关心的。

2. 模式的使用场景

发布订阅者模式中的事件驱动和解耦性,让我们非常方便地使用在一些场景中,比如ajax数据返回后的展示,厂家通知所有订阅用户新品已发布,异步登录,等等。

发布订阅者模式,可以让我们不再涉及更多的回调处理,而且可以使模块的颗粒度更小。比如有个ajax的数据展示,其中一个订阅者A可以只负责数据的表格展示,另一个订阅者B只负责数据总量的计算。当有需求要把数据总量的计算修改为当前页的数据总量和整体的数据总量计算,那么订阅者A是不用任何变动的!

2. 如何实现一个发布订阅者模式

在发布订阅者模式中,我们需要的功能有: 订阅,发布,取消订阅,还有一个列表来维护它们之间的订阅关系。

COPYJAVASCRIPT

var pubsub = {}; //订阅关系列表 ;(function(q){ var topics = [], subUid = -1; // 添加订阅者 q.subscribe = function(topic, func){ var token = (++subUid).toString(); if( !topics[topic] ){ topics[topic] = []; } topics[topic].push({ token : token, func : func }); return token; } // 触发 q.publish = function(topic, args){ var ss = topics[topic], len = ss ? ss.length: 0; // 取出订阅该主题所有的订阅者 while(len--){ var func = ss[len].func; func(topic, args); } } // 取消订阅 q.unsubscribe = function(token){ for(var key in topics){ if( topics[key] ){ var item; for(var i=0, len=topics[key].length; i<len; i++){ item = topics[key][i]; if( item.token===token ){ topics[key].splice(i, 1); } } } } } })(pubsub);

使用:

COPYJAVASCRIPT

// 展示数据 pubsub.subscribe('view', function(topic, args){ console.log( args ); }); // 计算数据总量 var token = pubsub.subscribe('count', function(topic, args){ console.log( args.length ); }) var data = [{name:'wenzi', age:26}]; pubsub.publish('view', data); pubsub.publish('count', data); pubsub.unsubscribe(token); // 取消订阅 pubsub.publish('count', data); // 不再执行

3. 总结

上面简单的实现了一下发布订阅者模式的模型,在样例代码中,我们也能够看到,发布者和订阅者之间仅仅依靠订阅关系来维持,而且发布者也不用关心订阅者的内部具体是怎么实现的。

在更复杂的场景中,代码也会变的更加复杂。蚊子的前端博客讲前端,欢迎各位提出宝贵的意见或建议!

标签:
阅读(741)

公众号:

qrcode

微信公众号:前端小茶馆

公众号:

qrcode

微信公众号:前端小茶馆