Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
TieMuZhen opened this issue Dec 9, 2021 · 0 comments
Open

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

TieMuZhen opened this issue Dec 9, 2021 · 0 comments

Comments

@TieMuZhen
Copy link
Owner

TieMuZhen commented Dec 9, 2021

观察者模式(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})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant