发布-订阅模式(Pub/Sub)的核心原理与实现

118 阅读2分钟

发布订阅模式

发布订阅是一种设计模式,它定义了一种一对多的关系,让多个观察对象同时监听某一个主题对象,当主题对象状态发生改变时,会通知所有的观察者对象,使他们能够执行各自的操作。

核心概念

  1. 发布者:产生并发送消息的组件,不直接将信息发送给特定的接收者。
  2. 订阅者:声明对某类信息感兴趣并接收相关消息的组件。
  3. 消息代理:中介组件,负责接收发布者的消息并根据订阅关系将消息分发给订阅者。
  4. 主题:消息的分类标识,订阅者通过订阅特定主题来接收相关消息。

主要特定

  • 松耦合:发布者和订阅者彼此不知道对方存在
  • 异步通信:消息的发送和接收可以不同步
  • 动态订阅:订阅关系可以运行时动态变更
  • 一对多传播:一条消息可以被多个订阅者接收

发布订阅的代码实现

class EventEmitter{
    constructor(){
         this.eventList={

         }
    }
  on(eventName,cb){
     if(!this.eventList[eventName]){
        this.eventList[eventName]=[]
     }
     this.eventList[eventName].push(cb)
  }
  emit(eventName){
    if(this.eventList[eventName]){
        const handeler=this.eventList[eventName].slice()
        handeler.forEach((item)=>{
            item()
        })
    }
  }
  off(eventName,cb){
    const callback=this.eventList[eventName]
    const index=callback.indexOf(cb)
    if(index!==-1)
    {
        callback.splice(index,1)
    }  
  }
   once(eventName,cb){
     const warp=()=>{
        cb()
        this.off(eventName,warp)
     }
    this.on(eventName,warp)
   }
}
// 创建事件发射器实例
const _event = new EventEmitter();

// 定义事件处理函数
function kang() {
    console.log('杨总买房子');
}
function ji() {
    console.log('刘总也买房子');
}
function cheng() {
    console.log('成哥买车位');
}
// 测试常规事件监听
_event.on('hasHouse', kang);
_event.on('hasHouse', ji);
// 测试一次性事件监听
_event.once('hasCar', cheng);
// 触发事件测试
console.log('--- 第一次触发 hasCar 事件 ---');
_event.emit('hasCar');  // 应该执行 cheng 函数

console.log('\n--- 第二次触发 hasCar 事件 ---');
_event.emit('hasCar');  // 不应该再执行,因为是一次性监听

console.log('\n--- 触发 hasHouse 事件 ---');
_event.emit('hasHouse');  // 应该执行 kang 和 ji 函数

// 测试取消监听
console.log('\n--- 取消 kang 的 hasHouse 监听后 ---');
_event.off('hasHouse', kang);
_event.emit('hasHouse');  // 现在应该只执行 ji 函数

}

测试结果

image.png

发布订阅模式实现思路(基于缓存列表)

  1. 创建缓存列表对象
  2. on方法(订阅事件)
  3. emit方法(发布事件)
  4. off方法(取消订阅)
  5. once方法(一次监听)额外功能

观察者模式

观察者模式是一种行为设计模式,它定义了一种一对多的依赖关系,当一个对象(被观察者)的状态发生改变时,所有依赖于它的对象(观察者)都会自动收到通知并执行相应更新。

发布订阅的代码实现

//1.被观察者(Subject)
class Subject{
    constructor(){
        this.observers=[]//存储观察者的数组
    }
    add(observer){
        this.observers.push(observer)
    }
    ontify(data){
        this.observers.forEach(observer=>observer(data))
    }
}
// 2.使用示例
const subject=new Subject()
const observer1=(data)=>{
    console.log('观察者1收到',data)
}
const observer2=(data)=>{
    console.log('观察者2收到',data)
}
subject.add(observer1)
subject.add(observer2)
subject.ontify('新消息')
// 输出
// 观察者1收到 新消息
// 观察者2收到 新消息