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订阅者,发布者和订阅者不直接通讯,通过调度中心来传递消息。

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

相关推荐
一点七加一20 分钟前
Harmony鸿蒙开发0基础入门到精通Day09--JavaScript篇
开发语言·javascript·ecmascript
_安晓22 分钟前
Rust 中精确大小迭代器(ExactSizeIterator)的深度解析与实践
java·前端·python
烛阴22 分钟前
从create到yield:Lua协程完全上手指南
前端·lua
薛一半1 小时前
Vue3的Pinia详解
前端·javascript·vue.js
浅影歌年2 小时前
vue3模块中引用公共css变量文件
前端
盼哥PyAI实验室3 小时前
从搭建到打磨:我的纯前端个人博客开发复盘
前端·javascript
前端初见3 小时前
2025前端面试题大合集
前端
用户904706683573 小时前
vue3.5新特性——useTemplateRef
前端
嘉琪0013 小时前
vue3+ts面试题(一)JSX,SFC
前端·javascript·react.js
何贤3 小时前
🪐 行星科技概念官网!Hero Section 回归!(Three.js ✨)
前端·javascript·three.js