观察者和发布订阅者模式

尽管观察者模式和发布订阅模式在某些方面相似,但它们在设计和使用上有一些关键的区别。以下是详细的对比:

  • 使用示例
javascript 复制代码
//观察者模式
class Subject { 
    constructor() { 
        this.observers = []; 
    } 
    addObserver(observer) { 
        this.observers.push(observer); 
    } 
    removeObserver(observer) { 
        this.observers = this.observers.filter((obs) => obs !== observer); 
    } 
    notify(data) { 
        this.observers.forEach((observer) => observer.update(data)); 
    } 
} 

class Observer { 
    constructor(name) { 
        this.name = name; 
    } 
    update(data) { 
        console.log(`${this.name} received data: ${data}`); 
    } 
} 

const subject = new Subject(); 
const observer1 = new Observer('Observer 1'); 
const observer2 = new Observer('Observer 2'); 
subject.addObserver(observer1); 
subject.addObserver(observer2); 
subject.notify('Hello Observers!'); 
// 输出: Observer 1 received data: Hello Observers! 
// Observer 2 received data: Hello Observers!
js 复制代码
//发布订阅模式
class EventEmitter { 
    constructor() { 
        this.events = {}; 
    } 
    subscribe(eventName, callback) { 
        if (!this.events[eventName]) { 
            this.events[eventName] = []; 
        } 
        this.events[eventName].push(callback);
    } 
    unsubscribe(eventName, callback) { 
        if (this.events[eventName]) { 
            this.events[eventName] = this.events[eventName].filter( (cb) => cb !== callback ); 
        } 
    } 
    publish(eventName, ...args) { 
        if (this.events[eventName]) { 
            this.events[eventName].forEach((callback) => { callback(...args); });
        }
    }
} 
const ee = new EventEmitter(); 
ee.subscribe('click', (arg) => { 
    console.log('click1' + arg); 
}); 
ee.publish('click', 121212); // 输出: click1121212   
  • 定义和角色
    • 观察者模式
      • 核心角色:

        Subject(主题):维护一个观察者列表,提供添加、删除观察者的方法,并在状态变化时通知所有观察者。

        Observer(观察者):定义一个更新接口,当主题状态变化时,观察者通过该接口接收通知并进行相应处理

      • 关系

        观察者和主题之间存在直接的依赖关系。观察者需要知道主题的存在,并且主题需要知道观察者的具体接口

    • 发布订阅模式
      • 核心角色:

        Publisher(发布者):发布事件或消息,但不需要知道订阅者的存在。

        Subscriber(订阅者):订阅特定事件或消息,并在事件发生时接收通知。

        Event Channel(事件通道:作为发布者和订阅者之间的中介,负责事件的分发。

      • 关系

        发布者和订阅者之间没有直接的依赖关系。发布者只需知道如何通过事件通道发布事件,而订阅者只需知道如何订阅和处理事件。

  • 解耦成都
    • 观察者模式
      • 耦合度较高:主题需要知道观察者的具体接口(如 update 方法),观察者也需要知道主题的存在。
      • 适用场景:适用于对象之间的关系相对固定且已知的情况
    • 发布订阅模式
      • 耦合度较低:发布者和订阅者之间通过事件通道进行通信,彼此不需要直接知道对方的存在。
      • 适用场景:适用于需要高度解耦的系统,特别是在大型系统中,组件之间的依赖关系复杂时。
  • 灵活性
    • 观察者模式
      • 灵活性有限:主题和观察者之间的关系是固定的,难以动态地添加或移除观察者。
      • 适用场景:适用于简单的、关系固定的场景。
    • 发布订阅模式
      • 灵活性高:可以动态地添加或移除订阅者,事件通道可以处理多种类型的事件。
      • 适用场景:适用于复杂的、需要动态管理的系统。
相关推荐
青柠之夏cc1 小时前
前端拖拽功能原生实现,不引入拖拽库完成业务
开发语言·前端·python
liangshanbo12152 小时前
前端大文件切片上传怎么做?
前端
Sand(ContextGate)2 小时前
Python Agent 测试实战:测试与评估,让 Agent 像传统软件一样可交付
前端·javascript·python·microsoft·ai
广州华水科技2 小时前
单北斗GNSS变形监测系统在城市安全与地质灾害中的应用前景
前端
颜进强2 小时前
20 · NestJs循环依赖与 forwardRef:容器为什么在环面前会死,"占位再补齐"怎么救
前端·后端·ai编程
颜进强2 小时前
19 · NestJs @Global 落地账:装饰器与 `isGlobal` 参数,各在什么场景上岗
前端·后端·ai编程
码艺-Alimjan3 小时前
Tauri 网站To桌面应用实战总结
前端·javascript·vue
颜进强3 小时前
18 · NestJS动态模块与 forRoot:`imports: [ConfigModule.forRoot({...})]` 到底在 import 什么
前端·后端·ai编程
YZ1225523 小时前
【Docker专题】使用Docker部署Vue-Flask项目前后端分离版【前端Docker部署】
前端·vue.js·docker
liangshanbo12153 小时前
浏览器渲染过程:高级前端面试题
前端