JS设计模式 之 发布-订阅模式

1、什么是发布-订阅模式

发布-订阅模式是属于经过解耦合的观察者模式。

让多个订阅者对象同时监听某一个调度中心,这个调度中心观察到发布者发生变化的时候,会通知所有的订阅者。

涉及的几个角色:

  • 订阅者:收到通知之后,可以更新自己
  • 调度中心:通知订阅者
  • 发布者:被调度中心监视

比如说我们上淘宝买一样东西,但是价格有点贵,所以我们可以把它加入淘宝的降价通知功能中去,这样子,当商家降低该商品的价格的时候,我们就能够收到对应的淘宝发出的通知。

这时候,淘宝就是一个调度中心,我们买家就是订阅者,卖家就是发布者。


2、发布-订阅模式有什么用?

解决了一个对象方式改变其他对象通知的问题,解耦他们之间的依赖关系。

你要买某样东西,你不需要在一直去关注物品的价格是否降低,会由淘宝来通知你,你只需要等待淘宝的信息,这样就实现了你和商家之间的解耦,你都不需要去知道商家的商品是涨价了还是降价了,反正当它一降价,淘宝就去通知你。

如图所示:

image


3、发布-订阅模式的优点与缺点

优点:

  • 解耦。像上方提到过的,通过发布订阅模式进行通信,通信双方不需要有任何的联系,只需要关注彼此的事件即可。
  • 广泛应用于异步编程当中。在异步编程中,我们是不知道结果什么时候会返回的,通常的办法就是通过传入一个回调函数,在异步结束后,调用这个回调函数,有值的话就将值作为回调的参数传入。但是在发布订阅中,只需要在外部去订阅一个事件,比方说 'ready' 事件,那么在异步结束的时候,就可以发布 'ready' 这个事件,那么订阅方就会执行它订阅的函数,并且发布事件也是可以传递参数的。

缺点:

  • 解耦,将两个对象解耦不仅是他的优点,也是它的缺点所在
    • 因为发布者不会去关心事件发布的结果,所以一旦事件发布结束想要进行反馈就没有办法。
    • 比方说上方的某个事件发布之后,订阅者做出了对应的操作,但是你没有办法通知发布者你执行了什么操作,你只能通过发布事件的方式在发一个事件回去。

4、发布-订阅模式代码实现

// 调度中心
class EventBus {
    constructor() {
        // 事件集
        this.handles = {};
    }

    // 订阅事件
    on(eventType, handle) {
        if (!this.handles.hasOwnProperty(eventType)) {
            this.handles[eventType] = [];
        }
        if (typeof handle == 'function') {
            this.handles[eventType].push(handle);
        } else {
            throw new Error('缺少回调函数');
        }
        return this; // 实现链式操作
    }

    // 发布事件
    emit(eventType, ...args) {
        if (this.handles.hasOwnProperty(eventType)) {
            this.handles[eventType].forEach((item, key, arr) => {
                item.apply(null, args);
            });
        } else {
            throw new Error(eventType + "事件未注册");
        }
        return this; // 实现链式操作
    }

    // 取消订阅
    off(eventType, handle) {
        if (!this.handles.hasOwnProperty(eventType)) {
            throw new Error(eventType + "事件未注册");
        } else {
            this.handles[eventType].forEach((item, key, arr) => {
                if (item == handle) {
                    arr.splice(key, 1);
                }
            });
        }
        return this; // 实现链式操作
    }
}


let eventBus = new EventBus();

// 发布者
class Publisher {
    constructor() {}

    lowPrice(price) {
        // 发布lowPrice事件
        eventBus.emit('lowPrice', price);
    }
}

// 订阅者
class Subscriber {
    constructor() {}

    lowPriceHandle(price) {
        console.log("目前最低价是:" + price + "元");
    }
    
    getLowPrice() {
        // 订阅lowPrice事件
        eventBus.on('lowPrice', this.lowPriceHandle);
    }

    offLowPrice() {
        eventBus.off('lowPrice', this.lowPriceHandle);
    }
}

// 订阅者订阅了关于某个商品最新促销价的消息
const subscriber = new Subscriber();
subscriber.getLowPrice();

// 发布者发布了某个商品的最新促销价
const publisher = new Publisher();
publisher.lowPrice(100); // test.html:76 目前最低价是:100元

// 订阅者取消订阅
subscriber.offLowPrice();
publisher.lowPrice(200);

学习参考:

设计模式 - js 发布订阅模式

posted @ 2022-12-07 14:31  笔下洛璃  阅读(781)  评论(0编辑  收藏  举报