为什么要使用Publish/Subscribe设计模式

解耦,解耦,解耦
我们都希望每个component做到独立,方便复用
但同时又希望它们之间存在联系
这时候就需要publish/subscribe模式
以MC*框架为例,通常Model层会处理很多业务相关的逻辑,它需要和很多个View模块进行交互
这时候如果采用p/s模式,Model层就只需要publish一个event,相关的View模块就会接收到,进行更新
我们也可以把这种模式认为是Observer模式

Publish/Subscribe模式的实现

实现一:利用jQuery的callbacks

var topics = {};
jQuery.Topic = function(id){
    var callbacks, topic = topics[id];
    if (!topic) {
        callbacks = jQuery.Callbacks();
        topic = {
            publish: callbacks.fire,
            subscribe: callbacks.add,
            unsubscribe: callbacks.remove
        };
        topics[id] = topic;
    }
    return topic;
}
var messageHandler = function(data) {
    console.log("a publish has occurred, get data:" + data);
};
$.Topic("message").subscribe(messageHandler);
$.Topic("message").publish('send');
$.Topic("message").unsubscribe(messageHandler);

实现二:原生js

var pubsub = {};
(function(myObject){
    //Storage for topic which can be broadcast or listened to.
    var topics = {};
    var uid = -1;
    myObject.publish = function(topic, args) {
        if (topics[topic] && topics[topic].length) {
            topics[topic].forEach(function(t){
                t.fn(topic, args);
            });
        }
    };
    myObject.subscribe = function(topic, fn) {
        if (!topics[topic]) {
            topics[topic] = [];
        }
        var token = (++uid).toString();
        topics[topic].push({
            token: token,
            fn: fn
        });
        return token;
    };
    myObject.unsubscribe = function(token) {
        for (var i in topics) {
            if (topics.hasOwnProperty(i)) {
                for (var len = topics[i].length; len--;){
                    if (topics[i][len].token === token) {
                        topics[i].splice(len, 1);
                        return token;
                    }
                }
            }
        }
        return this;
    };

})(pubsub);
//subscribe listener for topic "newMessage"
var token = pubsub.subscribe('newMessage', function(topic, a){console.log("Log1:"+ a)});
//Also, you can subscribe listener2 for same topic
var token2 = pubsub.subscribe('newMessage', function(topic, a){console.log("Log2:"+ a)});
//publish topic "newMessage", both log1 and log2 comes out
pubsub.publish('newMessage', 'Hello');
//unsubscribe for unique token which is generated by subscribing listener
pubsub.unsubscribe(token2);
//only log1 comes out
pubsub.publish('newMessage', 'Hello');