JS設計模式初識(十)-職責鏈模式

定義

職責鏈模式的定義是:使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關係,將這些對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有一個對象處理它爲止。 相似於上級分配給給下級任務...ajax

職責鏈模式的最大優勢:請求發送者只須要知道鏈中的第一個節點,從而弱化了發送者和一組接收者之間的強聯繫。咱們只須要將硬幣傳遞個面前的人,直到給到售票員手裏,算是這個任務結束。若是不使用職責鏈模式,我就得先搞清楚誰是售票員,才能把硬幣遞給他。bash

10.1 訂單案例

公司針對支付過定金的用戶有必定的優惠政策。app

  • 500元定金的用戶: 會收到100元的商城優惠券,異步

  • 200元定金的用戶: 能夠收到50元的優惠券,函數

  • 普通用戶: 無優惠券,且受到庫存的影響網站

  • 而以前沒有支付定金的用戶自動降級爲普通購買模式,ui

  • orderType: 1: 500元定金用戶, 2: 200元 , 3: 普通用戶this

  • isPay: 是否支付過 true: 是, false: 否spa

  • stock 庫存量prototype

10.2 實現需求

// 訂單函數
    function order(orderType, isPay, stock) {
        if (orderType === 1) {
            if (isPay) {
                console.log(' => 500元定金用戶, 獲得100元優惠券',);
            } else {
                if (stock > 0) {
                    console.log(' => 普通用戶, 無優惠券',);
                }
            }
        } else if (orderType === 2) {
            if (isPay) {
                console.log(' => 200元定金用戶, 獲得50元優惠券',);
            } else {
                if (stock > 0) {
                    console.log(' => 普通用戶, 無優惠券',);
                }
            }
        } else {
            if (stock > 0) {
                console.log(' => 普通用戶, 無優惠券',);
            } else {
                console.log(' => 庫存不足',);
            }
        }
    }
    order( 1 , true, 500); // 輸出: 500 元定金預購, 獲得 100 優惠券
複製代碼

10.2 改進一下

上面的實現使用了太多的if else 致使代碼很亂,很難懂, 下面稍微改進一下

function order500(orderType, isPay, stock) {
        if (orderType === 1 && isPay) {
            console.log(' => 500元定金用戶, 獲得100元優惠券',);
        } else {
            order200(orderType, isPay, stock); // order200 和 order500 耦合在一塊兒
        }
    }
    
    function order200(orderType, isPay, stock) {
        if (orderType === 2 && isPay) {
            console.log(' => 200元定金用戶, 獲得50元優惠券',);
        } else {
            orderNormal(orderType, isPay, stock);
        }
    }
    
    function orderNormal(orderType, isPay, stock) {
        if (stock > 0) {
            console.log(' => 普通用戶, 無優惠券',);
        } else {
            console.log(' => 庫存不足',);
        }
    }
複製代碼

可是這個函數有個很明顯的問題, 就是 order500和order200 是牢牢耦合在一塊兒的

10.3 使用職責鏈模式改進函數

function Chain(fn) {
        this.fn = fn;
        this.next = null;
    }
    Chain.prototype.setNext = function(next) {
        return this.next = next;
    }
    Chain.prototype.passRequest = function(...args) {
        let ret = this.fn.apply(this, next);
        if (ret === 'successToNext') { // 自動調用下一個函數
            return this.next();
        }
        return ret;
    }
    // 手動調用下一個
    Chain.prototype.next = function() {
        return this.next && this.next.apply(this.next, args);
    }
    
    // 生成鏈節點
    const ChainOrder500 = new Chain(order500);
    const ChainOrder200 = new Chain(order200);
    const ChainOrderNormal = new Chain(orderNormal);
    
    // 設置鏈節點執行順序
    ChainOrder500.setNext(ChainOrder200).setNext(ChainOrderNormal);
    
    // 傳給第一個節點
    chainOrder500.passRequest( 1, true, 500 );
複製代碼

經過改進,咱們能夠自由靈活地增長、移除和修改鏈中的節點順序,假如某天網站運營人員 又想出了支持 300 元定金購買,那咱們就在該鏈中增長一個節點便可

var order300 = function(){ // 具體實現略 };
    chainOrder300= new Chain(order300); 
    chainOrder500.setNext(chainOrder300).setNext(chainOrder200);;
複製代碼

改進以前:

使用職責鏈改進後:

這個請求或者任務 會在往下傳遞, 直到有人接手完成了它,不然會一直傳遞下去,這個相似於 上級給一層層下級傳遞任務。

10.4 異步的職責鏈

// 異步職責鏈
    const fn1 = new Chain(() => {
        console.log(' => fn1',);
        return 'successToNext';
    });
    const fn2 = new Chain(() => {
        console.log(' => fn2',);
        // 發送ajax success callback
        setTimeout(() => {
            this.next();
        }, 2000);
    });

    const fn3 = new Chain(() => {
        console.log('fn3 => ',);
    });

    fn1.setNext(fn2).setNext(fn3);
    fn1.passRequest();
複製代碼

10.5 總結

  • 使用了職責鏈模式以後,鏈中的節點對象能夠靈活地拆分重組。增長或者刪除一個節點,或者改變節點在鏈中的位置都是垂手可得的事情。這一點咱們也已經看到,在上面的例子中, 增長一種訂單徹底不須要改動其餘訂單函數中的代碼。

  • 實際上只要運用得當,職責鏈模式能夠很好地幫助咱們管理代碼,下降發起請求的對象和處理請求的對象之間的耦合性。職責鏈中的節點數量和順序是能夠自由變化的,咱們能夠在運行時決定鏈中包含哪些節點。

相關文章
相關標籤/搜索