JS設計模式——職責鏈模式

職責鏈模式閉包

1. 職責鏈定義

使多個對象都有機會處理請求,從而避免請求的發送者和接受者之間的耦合關係,將對象連成一條鏈,並沿着這個鏈傳遞該請求,直到有一個對象處理它爲止app

2.職責鏈優勢

請求發送者只須要知道鏈中的第一個節點,從而弱化了發送者和一組接受者之間的強聯繫異步

3.職責鏈缺點

職責鏈模式使得程序中多了一些節點對象,在某次請求傳遞過程當中,大部分節點並無實質性做用,只是讓請求傳遞下去,從性能方面考慮,要避免過長的職責鏈帶來的性能耗損函數

4.職責鏈使用場景

4.1 基礎例子

商城作活動,預付定金500且購買的客戶可返現100,預付定金200且購買的客戶可返現50,普通購買則沒有返現且庫存不夠買不到。性能

//設置每一個節點的操做,即每種用戶對應的操做,若是不能該節點不能操做則傳遞給下一個節點。
var order500 = function (orderType, pay, stock) {
    if (orderType === 1 && pay === true) {
        console.log("100")
    } else {
        return 'nextSuccessor'
    }
}
var order200 = function (orderType, pay, stock) {
    if (orderType === 2 && pay === true) {
        console.log('50')
    } else {
        return 'nextSuccessor'
    }
}
var order = function (orderType, pay, stock) {
    if (stock > 0) {
        console.log('buy')
    } else {
        console.log('lack')
    }
}
//職責鏈,規定每一個節點的下一個節點,執行本節點的函數
function Chain(fn) {
    this.fn = fn
    this.nextSuccessor = null
}
Chain.prototype.setNextSuccessor = function (successor) {
    this.nextSuccessor = successor
}
Chain.prototype.passRequest = function () {
    var ret = this.fn.apply(this, arguments)
    if (ret === 'nextSuccessor') {
        return this.nextSuccessor && this.nextSuccessor.passRequest.apply(this.nextSuccessor, arguments)
    }
}
//把每一個節點都放到職責鏈中
var chainOrder500 = new Chain(order500)
var chainOrder200 = new Chain(order200)
var chainOrder = new Chain(order)
//設置職責鏈的下一個節點
chainOrder500.setNextSuccessor(chainOrder200)
chainOrder200.setNextSuccessor(chainOrder)
//設定從某個職責鏈節點開始執行
chainOrder500.passRequest(1, true, 1)

4.2 異步職責鏈

//設置每一個節點的操做,即每種用戶對應的操做,若是不能該節點不能操做則傳遞給下一個節點。
var order500 = function (orderType, pay, stock) {
    if (orderType === 1 && pay === true) {
        console.log("100")
    } else {
        return 'nextSuccessor'
    }
}
var order200 = function (orderType, pay, stock) {
    var self = this
    setTimeout(function () {
        self.next()
    }, 1000)
    // if (orderType === 2 && pay === true) {
    //     console.log('50')
    // } else {
    //     return 'nextSuccessor'
    // }
}
var order = function (orderType, pay, stock) {
    if (stock > 0) {
        console.log('buy')
    } else {
        console.log('lack')
    }
}
//職責鏈,規定每一個節點的下一個節點,執行本節點的函數
function Chain(fn) {
    this.fn = fn
    this.nextSuccessor = null
}
Chain.prototype.setNextSuccessor = function (successor) {
    this.nextSuccessor = successor
}
Chain.prototype.passRequest = function () {
    var ret = this.fn.apply(this, arguments)
    if (ret === 'nextSuccessor') {
        return this.nextSuccessor && this.nextSuccessor.passRequest.apply(this.nextSuccessor, arguments)
    }
}
Chain.prototype.next = function () {
    return (this.nextSuccessor) && this.nextSuccessor.passRequest.apply(this.nextSuccessor, arguments)
}
// 把每一個節點都放到職責鏈中
var chainOrder500 = new Chain(order500)
var chainOrder200 = new Chain(order200)
var chainOrder = new Chain(order)
//設置職責鏈的下一個節點
chainOrder500.setNextSuccessor(chainOrder200)
chainOrder200.setNextSuccessor(chainOrder)
// 設定從某個職責鏈節點開始執行
chainOrder500.passRequest(1, false, 1)

這裏須要增長一個next函數,手動傳遞到下一個節點。this

4.3 用AOP實現職責鏈

var order500 = function (orderType, pay, stock) {
    if (orderType === 1 && pay === true) {
        console.log("100")
    } else {
        return 'nextSuccessor'
    }
}
var order200 = function (orderType, pay, stock) {
    if (orderType === 2 && pay === true) {
        console.log('50')
    } else {
        return 'nextSuccessor'
    }
}
var order = function (orderType, pay, stock) {
    if (stock > 0) {
        console.log('buy')
    } else {
        console.log('lack')
    }
}

Function.prototype.after = function (fn) {
    var self = this
    return function () {
        var ret = self.apply(this, arguments)
        if (ret === 'nextSuccessor') {
            return fn && fn.apply(this, arguments)
        }
        return ret
    }
}
var func = order500.after(order200).after(order)
func(1, true, 3)

這裏使用self變量存儲上一個函數,func存儲的是最後一個調用after返回的函數。一旦調用func函數,會先執行self保存的函數,會追根溯源一直到到最開始的self保存的函數order500。這裏利用了閉包的特性保留了每個self變量。整個函數的執行過程有點像倒序的遞歸。理解了過程也就會知道return ret這句代碼是爲後面的函數準備的~prototype

5. 建議

若是某塊功能中存在大量的if else能夠考慮使用職責鏈模式code

相關文章
相關標籤/搜索