发布订阅模式,又叫做观察者模式,描述对象间的一对多依赖关系。我举几个常见例子以便理解:报纸或杂志发布订阅、js编程中的事件模型、手机流量超限制提醒等等

使用场景

  1. 应用于异步编程,替代传统回调。

       用它的好处是可以切换我们的关注点,关注点集中在订阅事件,而在异步回调中我们需要关注内部运行状态。
    
  2. 取代对象之间的硬编码机制,对象之间不必再显式调用。

       优点是对象间达到松耦合,缺点是当有多个发布者和订阅者嵌套时,极难debug。
    

实战例子:

browser 中通过发布订阅模式实现事件机制,可直接执行

let EventP=(() => {
    let clientList={},  //订阅回调函数
        listen,  //监听器
        trigger,//触发器
        remove;
    listen= (key,fn) => {
        if(! clientList[key]){
            clientList[key]=[];
        }
       clientList[key].push(fn);
    };
    trigger= (...rest) => {
        let key=rest.shift(),
            fns=clientList[key];
        if(!fns||fns.length===0){
            return false;
        }
        fns.forEach(function (val,index) {
            val.apply(this,rest);
        });
    }
    remove=(key,fn) => {
        let fns=clientList[key];
        if(!fns){
            return false;
        }
        if(!fn){
            fns && (fns.length =0);
        }else{
            fns.forEach(function (val,index) {
                if(val==fn){
                    fns.splice(index,1);
                }
            });
        }
    };
    return{
        listen:listen,
        trigger:trigger,
        remove:remove,
    }
})();

EventP.listen('console',(info) => {
    console.log(info);
})


EventP.trigger('console','hello gcy');  //hello gcy

node当中已内置实现,下面是应用案例

let util= require('util');
let events = require('events');
function PC() {
    events.EventEmitter.call(this);
}
// util.inherits  //封装了es5的Object.create
util.inherits(PC,events.EventEmitter);


//equivalent  writing
// function PC() {
//     events.EventEmitter.call(this);
//     for(let tmpName in Event.EventEmitter.prototype){
//         this[tmpName]=Event.EventEmitter.prototype[tmpName];
//     }
// }

let pcInstance=new PC();
/**
 * keyInput 可以添加多个listeners
 */
pcInstance.on('keyInput',(track) => {
    console.log("track input",track);
});
let inputEnd=() => {
    console.log("input End");
}
pcInstance.on('keyInput',inputEnd);

/**
 *移除监听,必须有引用
 */
// pcInstance.removeListener('keyInput',inputEnd);

pcInstance.emit('keyInput','hello world gcy');

// ----------------------------------------------------------------------
// 对象组织事件名称,以便维护,模块复用
// let e={
//     keyInput:'keyInput',
//     charge:'charge'
//         ........
// }

//

说明 在node中我认为event的出现是为了解决异步问题(一般是事件驱动型)。event的本质是观察者模式的realize。它是base class之一


jsdt
4.9k 声望3.9k 粉丝

make a little progress every day