职责链模式

1. 职责链定义

使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系,将对象连成一条链,并沿着这个链传递该请求,直到有一个对象处理它为止

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函数,手动传递到下一个节点。

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这句代码是为后面的函数准备的~

5. 建议

如果某块功能中存在大量的if else可以考虑使用职责链模式


LJun
60 声望2 粉丝