1. 程式人生 > 其它 >JS設計模式 之 釋出-訂閱模式

JS設計模式 之 釋出-訂閱模式

1、什麼是釋出-訂閱模式

釋出-訂閱模式是屬於經過解耦合的觀察者模式。

讓多個訂閱者物件同時監聽某一個排程中心,這個排程中心觀察到釋出者發生變化的時候,會通知所有的訂閱者。

涉及的幾個角色:

  • 訂閱者:收到通知之後,可以更新自己
  • 排程中心:通知訂閱者
  • 釋出者:被排程中心監視

比如說我們上淘寶買一樣東西,但是價格有點貴,所以我們可以把它加入淘寶的降價通知功能中去,這樣子,當商家降低該商品的價格的時候,我們就能夠收到對應的淘寶發出的通知。

這時候,淘寶就是一個排程中心,我們買家就是訂閱者,賣家就是釋出者。


2、釋出-訂閱模式有什麼用?

解決了一個物件方式改變其他物件通知的問題,解耦他們之間的依賴關係。

你要買某樣東西,你不需要在一直去關注物品的價格是否降低,會由淘寶來通知你,你只需要等待淘寶的資訊,這樣就實現了你和商家之間的解耦,你都不需要去知道商家的商品是漲價了還是降價了,反正當它一降價,淘寶就去通知你。

如圖所示:


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 釋出訂閱模式