美文网首页
观察者模式和发布订阅模式区别

观察者模式和发布订阅模式区别

作者: Mica_马超 | 来源:发表于2021-06-07 08:51 被阅读0次

观察者模式

所谓观察者模式,其实就是为了实现松耦合(loosely coupled)。

在观察者模式中,观察者需要直接订阅目标事件;在目标发出内容改变的事件后,直接接收事件并作出响应


 ╭─────────────╮  Fire Event  ╭──────────────╮
 │             │─────────────>│              │
 │   Subject   │              │   Observer   │
 │             │<─────────────│              │
 ╰─────────────╯  Subscribe   ╰──────────────╯

实现:

class Subject {
    constructor() {
        this.observers = [];
    }
    
    add(observer) {
        this.observers.push(observer);
    }
    
    notify(...args) {
        this.observers.forEach(observer => observer.update(...args));
    }
}

class Observer {
    update(...args) {
        console.log('do something');
    }
}

const sub = new Subject(); /* 系统 */
sub.add(new Observer()); /* 张三点了预约 */
sub.add(new Observer()); /* 李四点了预约 */
sub.notify(); /* 双十一了,通知所有点了预约的人来抢货了 */

发布订阅模式

发布订阅模式属于广义上的观察者模式

发布订阅模式是最常用的一种观察者模式的实现,并且从解耦和重用角度来看,更优于典型的观察者模式


 ╭─────────────╮                 ╭───────────────╮   Fire Event   ╭──────────────╮
 │             │  Publish Event  │               │───────────────>│              │
 │  Publisher  │────────────────>│ Event Channel │                │  Subscriber  │
 │             │                 │               │<───────────────│              │
 ╰─────────────╯                 ╰───────────────╯    Subscribe   ╰──────────────╯

在发布订阅模式中,发布者和订阅者之间多了一个发布通道;一方面从发布者接收事件,另一方面向订阅者发布事件;订阅者需要从事件通道订阅事件

实现:

class SubPub {
    constructor() {
        this.observers = {};
    }
    
    subscribe(topic, callback) {
        if (!this.observers[topic]) {
            this.observers[topic] = [];
        }
        
        this.observers[topic].push(callback);
    }
    
    publish(topic, ...args) {
        let callbacks = this.observers[topic] || [];
        
        callbacks.forEach(cb => cb.call(this, ...args));
    }
}

const subject = new SubPub(); /* 中介 */
subject.subscribe('两室一厅', () => { console.log('张三'); }); /* 张三想买一个两室一厅的房子 */
subject.subscribe('三室一厅', () => { console.log('李四') }); /* 李四想买一个三室一厅的房子 */
subject.subscribe('两室一厅', () => { console.log('王五'); }); /* 王五想买一个两室一厅的房子 */

subject.publish('两室一厅'); /* 当出现一个两室一厅的房子时,中介会通知张三和王五来看房 */

使用:

class EventEmitter {
  constructor() {
    this.events = {};
  }
  // 实现订阅
  on(type, callBack) {
    if (!this.events[type]) {
      this.events[type] = [callBack];
    } else {
      this.events[type].push(callBack);
    }
  }
  // 删除订阅
  off(type, callBack) {
    if (!this.events[type]) return;
    this.events[type] = this.events[type].filter((item) => {
      return item !== callBack;
    });
  }
  // 只执行一次订阅事件
  once(type, callBack) {
    function fn() {
      callBack();
      this.off(type, fn);
    }
    this.on(type, fn);
  }
  // 触发事件
  emit(type, ...rest) {
    this.events[type] &&
      this.events[type].forEach((fn) => fn.apply(this, rest));
  }
}
// 使用如下
// const event = new EventEmitter();

// const handle = (...rest) => {
//   console.log(rest);
// };

// event.on("click", handle);

// event.emit("click", 1, 2, 3, 4);

// event.off("click", handle);

// event.emit("click", 1, 2);

// event.once("dbClick", () => {
//   console.log(123456);
// });
// event.emit("dbClick");
// event.emit("dbClick");

观察者模式和发布订阅模式图例

image.png

相关文章

网友评论

      本文标题:观察者模式和发布订阅模式区别

      本文链接:https://www.haomeiwen.com/subject/szsosltx.html