Skip to content

发布订阅模式与观察者模式 #61

Open
@TieMuZhen

Description

@TieMuZhen

观察者模式(Observer Pattern)

观察者模式定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知,并自动更新。

发布订阅模式(Pub-Sub Pattern)

在现在的发布订阅模式中,称为发布者的消息发送者不会将消息直接发送给订阅者,这意味着发布者和订阅者不知道彼此的存在。在发布者和订阅者之间存在第三个组件,称为消息代理或调度中心或中间件,它维持着发布者和订阅者之间的联系,过滤所有发布者传入的消息并相应地分发它们给订阅者。

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

我们先来看下这两个模式的实现结构:

观察者模式: 观察者直接订阅(Subscribe)主题(Subject),而当主题被激活的时候,会触发(Fire Event)观察者里的事件。

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

我们再来看下这两个模式的代码案例:

观察者模式:

语文、数学、英语老师都找小明帮忙干活,小明干完活后会主动通知每一位老师,这样老师就知道小明干完活了

function People () {
    this.list = [];
}

People.prototype.public = function () {
    this.list.forEach((item) => {
        item()
    })
}

People.prototype.subscribe = function (target, fn) {
    target.list.push(fn);
}

const teacherChina = new People();
const teacherMath = new People();
const teacherEnglish = new People();

const studentMing = new People();

teacherChina.subscribe(studentMing, function () {
    console.log("小明打印好了文件");
})

teacherMath.subscribe(studentMing, function () {
    console.log("小明拿回了快递");
})

teacherEnglish.subscribe(studentMing, function () {
    console.log("小明给文件盖完了章");
})

studentMing.public()

发布订阅模式:

老师把作业写在了黑板上,有同学写完了就在黑板上写上名字,当老师看黑板的时候就知道谁写完了,不用跟学生交流。

const Blackboard = {
    topics: {},
    subscribe: function (topic, fn) {
        if (!this.topics[topic]) {
            this.topics[topic] = [];
        }
        this.topics[topic].push(fn);
    },
    publish: function (topic) {
        this.topics[topic] && this.topics[topic].forEach((item) => {
            item();
        })
    }
}

function People () {
    this.list = [];
}

People.prototype.subscribe = function (topic, fn) {
    Blackboard.subscribe(topic, fn)
}

People.prototype.publish = function (topic) {
    Blackboard.publish(topic);
}

const teacherChina = new People();
const teacherMath = new People();
const teacherEnglish = new People();

const student1 = new People();
const student2 = new People();
const student3 = new People();

teacherChina.subscribe("finshed_china_work", function () {
    console.log("有学生完成了语文作业");
})

teacherMath.subscribe("finshed_math_work", function () {
    console.log("有学生完成了数学作业");
})

teacherEnglish.subscribe("finshed_english_work", function () {
    console.log("有学生完成了英语作业");
})

student1.publish("finshed_china_work");
student2.publish("finshed_math_work");
student3.publish("finshed_english_work");

观察者模式和发布订阅模式具体的写法和区别没有官方的定义,下面这种写法反而更常见。

手写一个EventBus

function EventBus () {
    this.map = {};
}

EventBus.prototype.on = function(type, handle){
    this.map[type] = (this.map[type] || []).concat(handle);
}

EventBus.prototype.off = function(type, handle){
    if(this.map[type]){
        if(handle){
            const index = this.map[type].indexof(handle);
            this.map[type].splice(index, 1);
        }else{
            delete this.map[type];
        }
    }
}

EventBus.prototype.fire = function(type, data){
    this.map && this.map[type].forEach(handle => handle(data));
}

测试代码

const eventBus = new EventBus()

eventBus.on('click:btn', data => {
  console.log(data)
})

eventBus.fire('click:btn', {a: 1, b: 2})
eventBus.off('click:btn')
eventBus.fire('click:btn', {a: 1, b: 2})

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions