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

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

作者: 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