发布-订阅模式

217 阅读3分钟

发布订阅模式

一、什么是发布-订阅模式

发布-订阅模式其实是一种对象间一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知。

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

二、实现发布-订阅模式

1. 实现思路

  • 创建一个对象
  • 在对象上创建一个缓存列表(调度中心)
  • on 方法把函数 fn都加到缓存列表中(订阅者注册事件到调度中心)
  • emit方法取到arguments里第一个当做event,根据event值去执行对应缓存列表中的函数(发布者发布事件到调度中心,调度中心处理代码)
  • off方法根据event值取消订阅(取消订阅)
  • once方法只监听一次,调用完毕后删除缓存函数(订阅一次)

2. demo1

//公众号对象
let eventEmitter = {};

//缓存列表,存放event及fn
eventEmitter.list = {};

//订阅
eventEmitter.on = function (event, fn) {
    let _this = this;
    //如果对象中没有对应event的值,说明没有订阅过,给event创建缓存列表
    //如果有队形的event值,添加fn到对应event缓存列表里
    (_this.list[event] || (_this.list[event] = [])).push(fn);
    return _this;
};

//发布
eventEmitter.emit = function() {
    let _this = this;
    // 第一个参数是对应的 event 值,直接用数组的 shift 方法取出
    let event = [].shift.call(arguments),
        fns = [..._this.list[event]];
    //如果缓存列表里没有fn就返回false
    if (!fns || fns.length === 0) {
        return false;
    }
    //遍历event值对应的缓存列表,依次执行fn
    fns.forEach(fn => {
        fn.apply(_this, arguments);
    });
    return _this;
};
function user1 (content) {
    console.log('用户1订阅了:', content);
};

function user2 (content) {
    console.log('用户2订阅了:', content);
};

// 订阅
eventEmitter.on('article', user1);
eventEmitter.on('article', user2);

// 发布
eventEmitter.emit('article', 'Javascript 发布-订阅模式');

/*
    用户1订阅了: Javascript 发布-订阅模式
    用户2订阅了: Javascript 发布-订阅模式
*/

三、观察者模式与发布订阅模式区别

参考文献

img

  • 观察者模式:一个对象(称为subject)维持一系列依赖于它的对象(称为observer),将有关状态的任何变更自动通知给它们(观察者)。

  • 发布/订阅模式:基于一个主题/事件通道,希望接收通知的对象(称为subscriber)通过自定义事件订阅主题,被激活事件的对象(称为publisher)通过发布主题事件的方式被通知。

两种模式之间的差异

  • Observer模式要求观察者必须订阅内容改变的事件,定义了一个一对多的依赖关系;

  • Publish/Subscribe模式使用了一个主题/事件通道,这个通道介于订阅着与发布者之间;

  • 观察者模式里面观察者「被迫」执行内容改变事件(subject内容事件);发布/订阅模式中,订阅者可以自定义事件处理程序;

  • 观察者模式两个对象之间有很强的依赖关系;发布/订阅模式两个对象之间的耦合度低。