js 观察者模式和发布订阅模式的实现和区别

观察者模式

观察者模式中有两个重要元素,一个是主体(subject)一个是观察者(observer)。其中主体(subject)有删除,添加和通知等方法。观察者可以去更新等操作。

下面简单实现观察者模式:

js 复制代码
 class Subject{ // 主体
    constructor(){
        this.observers =[];
    }
    add(observer){
        this.observers.push(observer)
    }
    remove(observer){
        const index = this.observers.findIndex(item=>item===observer)
        if(index!=-1){
            this.observers.splice(index, 1);
        }
    }
    notify(){
        this.observers.forEach(item=>item.update());
    }
    
}

class Observer{  // 观察者
    constructor(name){
     this.name =name;
    }
    update(){
        console.log(this.name)
    }
}

//测试
let subject = new Subject();
let obsDog = new Observer('dog');
let obsCat = new Observer('cat');
sub.add(obsDog);
sub.add(obsCat);
sub.notify();

上述代码中,我们创建了 Subject 对象和两个 Observer 对象,当有关状态发生变更时则通过 Subject 对象的 notify 方法通知这两个 Observer 对象,这两个 Observer 对象通过 update 方法进行更新

发布订阅模式

发布订阅模式 主要有一个调度中心,有订阅,发布,取消订阅等方法。

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

下面简单实现发布订阅模式

js 复制代码
class PubSub {
    constructor() {
        this.subs = {}
    }
    // 订阅方法
    subscribe(key, fb) {
        if (!this.subs[key]) {
            this.subs[key] = [];
        }
        this.subs[key].push(fb);
    }
    // 发布方法
    publish(...arg) {
        let args = arg;
        let key = args.shift(); //取出key值
        let fns = this.subs[key];
        if(!fns || fns.length<=0) return;
        if (this.subs[key]) {
            this.subs[key].forEach(cb => cb(...args))
        }
    }
    // 取消订阅方法
    unsubscribe(key, cb) {
        if (this.subs[key]) {
            const cbIndex = this.subs[key].findIndex(e=> e === cb)
            if (cbIndex != -1) {
                this.subs[key].splice(cbIndex, 1);
            }
        }
        if (this.subs[key].length === 0) {
            delete this.subs[key];
        }
    }
    unsubscribeAll(key) {
        if (this.subs[key]) {
            delete this.subs[key];
        }
    }
}

// 测试:
const pubSub = new PubSub();
pubSub.subscribe('封神第一部', time => {
    console.log(`封神第一部开始时间${time}点`);
  })
  pubSub.subscribe('封神第二部', time => {
    console.log(`封神第二部开始时间${time}点`);
  })
  pubSub.publish('封神第一部', 7);  
  pubSub.publish('封神第二部', 11);

通过上面的实现我们发现观察者模式其实是一种直接通讯的方式,比如我们订阅了电影院的微信公众号,当电影院的每种电影上映时,都会对他的所有订阅者发起通知(notify)。

但是在发布订阅模式中多了一个调度中心,比如我们关注了电影院的微信公众号,A同学给电影院发消息只想看封神第一部这个电影,B同学给电影院发消息只想看孤注一掷。那么电影院就会在对应的电影上映时给对应的同学发送不同的消息。,A同学就只接收到封神第一部的开映时间,B同学只接收孤注一掷的开映时间。

总结:

观察者模式有观察者和主体,Subject中通过observers记录ObServer。

优点是:角色明确,Subject和Object要遵循约定的成员方法. 缺点是紧耦合

发布订阅模式有 Publisher发布者、调度中心、Subscribe订阅者,发布者和订阅者不直接通讯,通过调度中心来传递消息。

优点是松散耦合,灵活度高,通常应用在异步编程中, 缺点是:当事件类型变多时,会增加维护成本

相关推荐
艾小逗1 小时前
vue3中的effectScope有什么作用,如何使用?如何自动清理
前端·javascript·vue.js
小小小小宇4 小时前
手写 zustand
前端
Hamm4 小时前
用装饰器和ElementPlus,我们在NPM发布了这个好用的表格组件包
前端·vue.js·typescript
明似水5 小时前
Flutter 弹窗队列管理:支持优先级的线程安全通用弹窗队列系统
javascript·安全·flutter
小小小小宇5 小时前
前端国际化看这一篇就够了
前端
大G哥5 小时前
PHP标签+注释+html混写+变量
android·开发语言·前端·html·php
whoarethenext5 小时前
html初识
前端·html
小小小小宇5 小时前
一个功能相对完善的前端 Emoji
前端
m0_627827525 小时前
vue中 vue.config.js反向代理
前端
Java&Develop6 小时前
onloyoffice历史版本功能实现,版本恢复功能,编辑器功能实现 springboot+vue2
前端·spring boot·编辑器