如何自己搭建发布订阅模式

笔记

Posted by Wason on April 1, 2022

如何自己搭建发布订阅模式

观察者模式

什么是观察者模式(别称:发布-订阅模式)

  1. 观察者模式定义了对象间的一种一对多的依赖关系, 当一个对象的状态发生改变时, 所有依赖于它的对象都将得到通知, 并自动更新。观察者模式属于行为型模式, 行为型模式关注的是对象之间的通讯, 观察者模式就是观察者和被观察者之间的通讯。
  2. 观察者模式有一个别名叫“发布-订阅模式”, 或者说是“订阅-发布模式”, 订阅者和订阅目标是联系在一起的, 当订阅目标发生改变时, 逐个通知订阅者。我们可以用报纸期刊的订阅来形象的说明, 当你订阅了一份报纸, 每天都会有一份最新的报纸送到你手上, 有多少人订阅报纸, 报社就会发多少份报纸, 报社和订报纸的客户就是上面文章开头所说的“一对多”的依赖关系。

发布者模式

什么是发布者模式

  1. 其实24种基本的设计模式中并没有发布订阅模式, 上面也说了, 他只是观察者模式的一个别称。但是经过时间的沉淀, 似乎他已经强大了起来, 已经独立于观察者模式, 成为另外一种不同的设计模式。
  2. 在现在的发布订阅模式中, 称为发布者的消息发送者不会将消息直接发送给订阅者, 这意味着发布者和订阅者不知道彼此的存在。在发布者和订阅者之间存在第三个组件, 称为消息代理或调度中心或中间件, 它维持着发布者和订阅者之间的联系, 过滤所有发布者传入的消息并相应地分发它们给订阅者。
  3. 举一个例子, 你在微博上关注了A, 同时其他很多人也关注了A, 那么当A发布动态的时候, 微博就会为你们推送这条动态。A就是发布者, 你是订阅者, 微博就是调度中心, 你和A是没有直接的消息往来的, 全是通过微博来协调的(你的关注, A的发布动态)。

区别

观察者模式和发布订阅模式有什么区别?
观察者模式

发布订阅模式

  • 观察者模式: 观察者(Observer)直接订阅(Subscribe)主题(Subject),而当主题被激活的时候,会触发(Fire Event)观察者里的事件。
  • 发布订阅模式: 订阅者(Subscriber)把自己想订阅的事件注册(Subscribe)到调度中心(Topic),当发布者(Publisher)发布该事件(Publish topic)到调度中心,也就是该事件触发时,由调度中心统一调度(Fire Event)订阅者注册到调度中心的处理代码。

实现观察者模式

var eventBus = {
    events: {},
    addEvent: function (eventKey, fun) {
        if (!this.events[eventKey]) {
            this.events[eventKey] = [];
        }
        this.events[eventKey].push(fun);
    },
    emitEvents: function (eventKey) {
        this.events[eventKey].forEach(item=>{
            item();
        })
    },
    removeEvent: function (eventKey, fun) {
        for(let i=0; i<this.events[eventKey].length; i++) {
            let item = this.events[eventKey][i];
            if (item == fun){
                this.events[eventKey].splice(i,1);
                break;
            }
        }
    }
}

function fn() {
    console.log("1");
}
function fn2() {
    console.log("2");
}
eventBus.addEvent("事件1", fn)
eventBus.addEvent("事件1", fn2)
eventBus.emitEvents("事件1");
eventBus.removeEvent("事件1", fn2);
eventBus.emitEvents("事件1")
VM2514:26 1
VM2514:29 2
VM2514:26 1

实现发布订阅者模式:(两套类似写法):

------------------------写法1 start------------------------
var eventBus = {
    events: {},
    addEvent: function (eventKey, fun) {
        if (!this.events[eventKey]) {
            this.events[eventKey] = [];
        }
        this.events[eventKey].push(fun);
    },
    emitEvents: function (eventKey) {
        this.events[eventKey].forEach(item=>{
            item();
        })
    },
    removeEvent: function (eventKey, fun) {
        for(let i=0; i<this.events[eventKey].length; i++) {
            let item = this.events[eventKey][i];
            if (item == fun){
                this.events[eventKey].splice(i,1);
                break;
            }
        }
    }
}

var personEvent = {
    info: {age:"", name:""},
    add: function (eventKey, fun) {
        eventBus.addEvent(eventKey, fun);
    },
    emit: function (eventKey) {
        eventBus.emitEvents(eventKey);
    },
};

function fn() {
    console.log("1");
}
function fn2() {
    console.log("2");
}
personEvent.info = {age:17, name:"xiaomi"};
personEvent.add("事件1", fn)
personEvent.add("事件1", fn2)
personEvent.emit("事件1")

VM4061:36 1
VM4061:39 2
------------------------end------------------------

------------------------写法2 start------------------------
var eventBus = {
    events: {},
    addEvent: function (eventKey, fun) {
        if (!this.events[eventKey]) {
            this.events[eventKey] = [];
        }
        this.events[eventKey].push(fun);
    },
    emitEvents: function (eventKey) {
        this.events[eventKey].forEach(item=>{
            item();
        })
    },
    removeEvent: function (eventKey, fun) {
        for(let i=0; i<this.events[eventKey].length; i++) {
            let item = this.events[eventKey][i];
            if (item == fun){
                this.events[eventKey].splice(i,1);
                break;
            }
        }
    }
}

function personEvent(age, name) {
    this.age = age;
    this.name = name;
}
personEvent.prototype.add = (eventKey, fun) => {
    eventBus.addEvent(eventKey, fun);
}

personEvent.prototype.emit = (eventKey) => {
    eventBus.emitEvents(eventKey);
}

function fn() {
    console.log("1");
}
function fn2() {
    console.log("2");
}
function fn3() {
    console.log("3");
}

let _personEvent = new personEvent(17, "xiaomi");
_personEvent.add("事件1", fn);
_personEvent.add("事件1", fn2);
_personEvent.add("事件1", fn3);


_personEvent.emit("事件1");


VM3122:38 1
VM3122:41 2
VM3122:44 3
------------------------end------------------------

参考文章

如何自己实现一个发布观察者模式