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

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

相关推荐
uhakadotcom5 分钟前
Vite 与传统 Bundler(如 Webpack)在 Node.js 应用的性能对比
前端·javascript·面试
uhakadotcom17 分钟前
Socket.IO 简明教程:实时通信的基础知识
前端·javascript·面试
weixin_4578858222 分钟前
JavaScript智能对话机器人——企业知识库自动化
开发语言·javascript·自动化
机器视觉知识推荐、就业指导37 分钟前
QML 批量创建模块 【Repeater】 组件详解
前端·c++·qml
lmryBC4943 分钟前
golang接口-interface
java·前端·golang
慕斯策划一场流浪1 小时前
fastGPT—nextjs—mongoose—团队管理之团队列表api接口实现
开发语言·前端·javascript·fastgpt env文件配置·fastgpt团队列表接口实现·fastgpt团队切换api·fastgpt团队切换逻辑
LaoZhangAI1 小时前
【2025最新】Claude免费API完全指南:无需信用卡,中国用户也能用
前端
hepherd1 小时前
Flask学习笔记 - 模板渲染
前端·flask
LaoZhangAI2 小时前
【2025最新】Manus邀请码免费获取完全指南:5种稳定渠道+3个隐藏方法
前端