likes
comments
collection
share

发布订阅模式、观察者模式和 EventBus、EventEmitter

作者站长头像
站长
· 阅读数 13

观察者模式

通俗来讲,观察者模式指的是一个对象(Subject)维持一系列依赖于它的对象(Observer),当有关状态发生变更时 Subject 对象则通知一系列 Observer 对象进行更新。

在观察者模式中,Subject 对象拥有添加、删除和通知一系列 Observer 的方法等等,而 Observer 对象拥有更新方法等等。

Subject 对象添加了一系列 Observer 对象之后,Subject 对象则维持着这一系列 Observer 对象,当有关状态发生变更时 Subject 对象则会通知这一系列 Observer 对象进行更新。

// Subject 对象
function Subject() {
  this.observers = [];
};

Subject.prototype = {
  add(observer) {  // 添加
    this.observers.push(observer);
  },
  notify() {  // 通知
    let observers = this.observers;
    for (let i = 0; i < observers.length; i++) {
      observers[i].update();
    }
  },
  remove(observer) {  // 删除
    let observers = this.observers;
    for (let i = 0; i < observers.length; i++) {
      if (observers[i] === observer) {
        observers.splice(i, 1);
      }
    }
  },
};

// Observer 对象
function Observer(name) {
  this.name = name;
};

Observer.prototype = {
  update() {  // 更新
    console.log('my name is ' + this.name);
  }
};

let sub = new Subject();
let obs1 = new Observer('obs1');
let obs2 = new Observer('obs2');
sub.add(obs1);
sub.add(obs2);
sub.notify();  //my name is obs1 name is obs2

发布订阅模式

发布订阅模式指的是希望接收通知的对象(Subscriber)基于一个主题通过自定义事件订阅主题,发布事件的对象(Publisher)通过发布主题事件的方式通知各个订阅该主题的 Subscriber 对象。

const pubSub = {
  list: {},
  subscribe(key, fn) {  // 订阅
    if (!this.list[key]) {
      this.list[key] = [];
    }
    this.list[key].push(fn);
  },
  publish() {  // 发布
    const arg = arguments;
    const key = Array.prototype.shift.call(arg);
    const fns = this.list[key];

    if (!fns || fns.length <= 0) return false;

    for (let i = 0, len = fns.length; i < len; i++) {
      fns[i].apply(this, arg);
    }
  },
  unSubscribe(key) {  // 取消订阅
    delete this.list[key];
  }
};

// 进行订阅
pubSub.subscribe('name', (name) => {
  console.log('your name is ' + name);
});
pubSub.subscribe('sex', (sex) => {
  console.log('your sex is ' + sex);
});
// 进行发布
pubSub.publish('name', 'nameValue');  // your name is nameValue
pubSub.publish('sex', 'male');  // your sex is male

观察者模式 VS 发布订阅模式

个人理解,观察者模式维护的是一个事件和多个依赖这个事件的对象之间的关系:

event->[obj1,obj2obj3,....]

发布订阅模式是多个事件(主题)和依赖于该事件(主题)的对象之间的关系:

{  
    event1->[obj1,obj2....],  
    event2->[obj1,obj2.....],
    ....
}

从表面上看:

  • 观察者模式里,只有两个角色——观察者 +  被观察者
  • 发布订阅模式里面,却不仅仅只有发布者和订阅者两个角色,还有一个经常被我们忽略的——Broker

往更深层级讲:

  • 观察者和被观察者,是松耦合的关系
  • 发布者和订阅者,则完全不存在耦合

从使用层面上讲:

  • 观察者模式,多用于单个应用内部
  • 发布订阅模式,则更多的是一种跨应用的模式,比如我们常用的消息中间件

EventBus

EventBus 和发布订阅模式非常相似,比如 Vue 中的 EventBus ,可以通过 $on 来订阅不同类型的主题,通过 $emit 发布不同的主题,该主题的订阅者就会执行相应 callback 函数。

class EventBus {
  constructor() {
    this.events = {}; // 存储事件及其对应的回调函数列表
  }

  // 订阅事件
  subscribe(eventName, callback) {
    this.events[eventName] = this.events[eventName] || []; // 如果事件不存在,创建一个空的回调函数列表
    this.events[eventName].push(callback); // 将回调函数添加到事件的回调函数列表中
  }

  // 发布事件
  publish(eventName, data) {
    if (this.events[eventName]) {
     this.events[eventName].forEach(callback => {
        callback(data); // 执行回调函数,并传递数据作为参数
      });
    }
  }

  // 取消订阅事件
  unsubscribe(eventName, callback) {
    if (this.events[eventName]) {
      this.events[eventName] = this.events[eventName].filter(cb => cb !== callback); // 过滤掉要取消的回调函数
    }
  }
}

// 使用

// 创建全局事件总线对象
const eventBus = new EventBus();

const callback1 = data => {
  console.log('Callback 1:', data);
};

const callback2 = data => {
  console.log('Callback 2:', data);
};

// 订阅事件
eventBus.subscribe('event1', callback1);
eventBus.subscribe('event1', callback2);

// 发布事件
eventBus.publish('event1', 'Hello, world!');

// 输出:
// Callback 1: Hello, world!
// Callback 2: Hello, world!

// 取消订阅事件
eventBus.unsubscribe('event1', callback1);

// 发布事件
eventBus.publish('event1', 'Goodbye!');

// 输出:
// Callback 2: Goodbye!

EventEmitter

class EventEmitter {
  constructor() {
    this.events = {}; // 用于存储事件及其对应的回调函数列表
  }

  // 订阅事件
  on(eventName, callback) {
    this.events[eventName] = this.events[eventName] || []; // 如果事件不存在,创建一个空的回调函数列表
    this.events[eventName].push(callback); // 将回调函数添加到事件的回调函数列表中
  }

  // 发布事件
  emit(eventName, data) {
    if (this.events[eventName]) {
      this.events[eventName].forEach(callback => {
        callback(data); // 执行回调函数,并传递数据作为参数
      });
    }
  }

  // 取消订阅事件
  off(eventName, callback) {
    if (this.events[eventName]) {
      this.events[eventName] = this.events[eventName].filter(cb => cb !== callback); // 过滤掉要取消的回调函数
    }
  }
  
  // 添加一次性的事件监听器 
  once(eventName, callback) { 
      const onceCallback = data => { 
          callback(data); // 执行回调函数 
          this.off(eventName, onceCallback); // 在执行后取消订阅该事件 
      }; 
      this.on(eventName, onceCallback); 
  }
}

//  使用
    const emitter = new EventEmitter();

    const callback1 = data => {
      console.log('Callback 1:', data);
    };
   
    const callback2 = data => {
      console.log('Callback 2:', data);
    };
    
    // 添加一次性事件监听器 
    const onceCallback = data => { 
        console.log('Once Callback:', data); 
    };
    
    // 订阅事件
    emitter.on('event1', callback1);
    emitter.on('event1', callback2);
    emitter.once('event1', onceCallback);
    
    // 发布事件
    emitter.emit('event1', 'Hello, world!');

    // 输出:
    // Callback 1: Hello, world!
    // Callback 2: Hello, world!
    // Once Callback: Hello, world!
    
    // 取消订阅事件
    emitter.off('event1', callback1);

    // 发布事件
    emitter.emit('event1', 'Goodbye!');

    // 输出:
    // Callback 2: Goodbye!

EventBusEventEmitter 有什么区别

至于EventBusEventEmitter 有什么区别,目前除了EventEmitter可以添加一次性监听事件,其余的我还没体会到,欢迎各位大佬指点~~

转载自:https://juejin.cn/post/7277882226595348536
评论
请登录