职责链模式的定义是:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
职责链模式的名字非常形象,一系列可能会处理请求的对象被该连接成一条链,请求在这些对象之间依次传递,直到遇到一个可以处理它的对象,我们把这些对象成为链中的节点。
现实中的职责链模式
挤公交车
高峰期挤上公交车必须一个个往前递钱让前面的人把钱交给售票员,最后才让售票员处理。
职责链的优点
请求发送者只需要知道链中的第一个节点,从而弱化了发送者和一组接收者之间的强联系。如果不使用职责链模式,那么在公交车上,必须先搞清楚谁是售票员,才能把硬币递给他。
开始实例开发
假设一个电视网站对于某部新上市的手机经过了2轮缴纳500元定金与200元定金的预定,现在已经到了正式购买的阶段。
支付了500元定金的用户在购买阶段可以使用100元优惠券,200元定金可以使用50元优惠券,普通用户没有如果没有库存不一定能买到。
订单页面时php模板,表单几个字段如下:
orderType: 表示订单类型(定金或者普通用户),code的值为1时候是500元定金用户,为2是200元定金用户,为3则是普通用户。
pay : 表示用户是否支付定金,用户虽然下过500元定金的订单但是如果他一直没有支付定金,那么只能降级为普通用户。
stock : 仅用户普通用户的库存数量,定金用户不受限制。
我们省略了使用普通代码进行开发的语句,因为实在太难看了太多的if语句,面向过程以后的维护工作恐怕是个梦魇。(其实是作者懒:)
职责链模式重构
参见代码:
// 500 order
var order500 = function (orderType,pay,stock) {
if(orderType === 1 && pay === true){
console.log('500 rmb deposit, get 100 coupon ')
} else {
order100(orderType,pay,stock) // req pass to 200 order
}
};
var order200 = function (orderType,pay,stock) {
if(orderType === 2 && pay === true){
console.log('200 rmb deposit , get 50 coupon')
} else{
orderNormal(orderType,pay,stock)
}
};
var orderNormal = function (orderType,pay,stock) {
if(stock > 0){
console.log('normal buy no coupon')
} else{
console.log('the stock lack')
}
};
//test result:
order500(1,true,500);
order500(2,true,500);
order500(3,true,500);
order500(1,false,500);
现在已经基本符合了职责链模式定义,下面实现灵活可拆分的职责链模式,我的意思就是不要像上述那样面向过程的从500传递到200然后再到普通,万一我们想传递到100呢? 岂不是还得要大修一番?
参见修改后的代码:
// 500 order
var order500 = function (orderType,pay,stock) {
if(orderType === 1 && pay === true){
console.log('500 rmb deposit, get 100 coupon ')
} else {
return 'nextSuccessor' // unknow the next node but always pass to next.
}
};
var order200 = function (orderType,pay,stock) {
if(orderType === 2 && pay === true){
console.log('200 rmb deposit , get 50 coupon')
} else{
return 'nextSuccessor';
}
};
var orderNormal = function (orderType,pay,stock) {
if(stock > 0){
console.log('normal buy no coupon')
} else{
console.log('the stock lack')
}
};
var Chain = function (fn) {
this.fn = fn;
this.successor = null;
}
Chain.prototype.setNextSuccessor = function (successor) {
return this.successor = successor;
}
Chain.prototype.passRequest = function () {
var ret = this.fn.apply(this.arguments);
if(ret === 'nextSuccessor'){
return this.successor && this.successor.passRequest.apply(this.successor,arguments)
}
return ret;
}
//现在我们把3个订单函数分别包装成职责链的节点
var chainOrder500 = new Chain(order500);
var chainOrder200 = new Chain(order200);
var chainOrderNormal = new Chain(orderNormal);
//最后把请求传递给第一个节点
chainOrder500.setNextSuccessor(chainOrder200)
chainOrder200.setNextSuccessor(chainOrderNormal)
//最后把请求传递给第一个节点
//test
chainOrder500.passRequest(1,true,500);
chainOrder500.passRequest(2,true,500);
//通过改进,我们可以自由灵活的增加移除和链中的节点顺序,假如我们 又想支持
//300元定金购买,那我们就在改链中增加一个节点即可:
var order300 = function () {
// todo
};
chainOrder300 = new Chain(chainOrder300)
chainOrder500.setNextSuccessor(chainOrder300)
chainOrder300.setNextSuccessor(chainOrder200)
小结
只要运用得当职责链模式可以很好的帮助我们管理代码。