上次研究观察者模式,很多文章说它也叫Subscribe/Publish(发布/订阅模式)。可在《Javascript设计模式》一书中,这两种模式还是有些区别的。书中原话如下:
1.Observer模式要求希望接收到主题通知者的观察者必须订阅内容改变的事件。
2.Subscribe/Publish模式使用了一个主题/事件通道,这个通道介于订阅者和发布者之间。该事件系统允许代码定义应用程序的特定事件,该事件可以传递自定义参数,自定义参数包含订阅者所需要的值。其目的是避免订阅者和发布者产生依赖关系。
与Observer模式不同之处在于它允许任何订阅者执行适当的事件处理程序来注册和接收发布者发出的通知。
好吧,不明觉厉。下面是我的理解:
1.观察者模式中,目标对象负责维护观察者。发布/订阅模式中发布者不关心订阅者,只负责把消息丢出去就不管了。
2.观察者模式中,观察者要提供一个接口,然后当目标对象发生改变时调用此接口使自身状态和目标状态保持一致。即所有的观察者都要有一个统一的接口(比如上文中写的update方法,大家的方法都要叫这个名字)。而发布/订阅模式中,订阅者事件的触发不是依靠这样一个接口,而是订阅者通过监听一个特定的消息(这个消息一般包含名称和订阅者所需要的参数)来触发的。可以理解为订阅者监听的不是发布者,而是消息池,只要消息池里有它关心的消息,即触发事件,不管这个消息是谁发布过去的。发布者和订阅者是解耦的。
下面是js中发布/订阅模式的实现,复制粘贴到console里面试一试就明白了:
var pubsub = (function(){ var q = {} topics = {}, subUid = -1; //发布消息 q.publish = function(topic, args) { if(!topics[topic]) {return;} var subs = topics[topic], len = subs.length; while(len--) { subs[len].func(topic, args); } return this; }; //订阅事件 q.subscribe = function(topic, func) { topics[topic] = topics[topic] ? topics[topic] : []; var token = (++subUid).toString(); topics[topic].push({ token : token, func : func }); return token; }; return q; //取消订阅就不写了,遍历topics,然后通过保存前面返回token,删除指定元素 })(); //触发的事件 var logmsg = function(topics, data) { console.log("logging:" + topics + ":" + data); } //监听指定的消息'msgName' var sub = pubsub.subscribe('msgName', logmsg); //发布消息'msgName' pubsub.publish('msgName', 'hello world'); //发布无人监听的消息'msgName1' pubsub.publish('anotherMsgName', 'me too!');