问题抛出:
双十一马上到了,一年一度的促销大战一触即发。于是我司特推出“预交订金购买手机,送代金券活动”。
活动如下:预交500元,送100元代金卷,预交200元,送50元代金卷。
根据本活动内容,让我司前端同学,给出编码提示:
一个刚入司的小A同学,感觉没有什么困难,写出如下代码
/***
** orderType 表示订单类型
** pay 表示用户是否已经支付定金
** stock 表示普通购买的手机库存数量
*/
const order = function (orderType, pay, stock) {
if (orderType === 1) {
if (pay === true) {
console.log('500元定金预购,得到100元优惠券')
} else {
if (stock > 0) {
console.log('普通用户购买,无优惠券')
} else {
console.log('手机库存不足')
}
}
} else if (orderType === 2) {
if (pay === true) {
console.log('200元定金购买,得到50元优惠卷')
} else {
if (stock > 0) {
console.log('普通购买,五优惠卷')
} else {
console.log('手机库存不足')
}
}
} else if (orderType === 3) {
if (stock > 0) {
console.log('普通用户购买,无优惠券')
} else {
console.log('手机库存不足')
}
}
}
order(1,true,500)
小B同学,阅读了小A的同学的代码后,感觉代码耦合性太高。如果需求一有变动,就需要重新修改上面的代码。于是写出了自己的代码如下:
/***
** orderType 表示订单类型
** pay 表示用户是否已经支付定金
** stock 表示普通购买的手机库存数量
*/
const order500 = function (orderType, pay, stock) {
if (orderType === 1 && pay === true) {
console.log('500元定金预购,得到100元代金券')
} else {
order200(orderType, pay, stock);
}
}
const order200 = function (orderType, pay, stock) {
if (orderType === 2 && pay === true) {
console.log('200元定金购买,得到50元代金券')
} else {
orderNormal(orderType, pay, stock)
}
}
const orderNormal = function (orderType, pay, stock) {
if (stock > 0) {
console.log('普通购买,无优惠卷')
} else {
console.log('手机库存不足')
}
}
//测试结果
order500(1, true, 500)
order500(1, false, 500)
order500(2, true, 500)
order500(3, false, 500)
order500(3, false, 0)
小C同学看了小B的代码后,感觉比小A的同学便于阅读了,但是感觉还是没有完全解耦,order500中含有order200的调用。请求在链条传递中的顺序比较僵硬,传递请求的代码还是耦合再来业务函数中,依然违反开放-封闭原则,如果有一天要增加哦300元预订或者去掉200元预定,意味着就必须修改业务函数内部。我们能不能灵活拆分掉他们呢?小C同学在小B的基础上,做了如下修改
/***
** orderType 表示订单类型
** pay 表示用户是否已经支付定金
** stock 表示普通购买的手机库存数量
*/
const order500 = function (orderType, pay, stock) {
if (orderType === 1 && pay === true) {
console.log('500元定金预购,得到100元代金券')
} else {
return 'nextSuccessor'
}
}
const order200 = function (orderType, pay, stock) {
if (orderType === 2 && pay === true) {
console.log('200元定金购买,得到50元代金券')
} else {
return 'nextSuccessor'
}
}
const orderNormal = function (orderType, pay, stock) {
if (stock > 0) {
console.log('普通购买,无优惠卷')
} else {
console.log('手机库存不足')
}
}
//测试结果
const Chain = function (fn) {
this.fn = fn;
this.successor = null;
}
// 指定链条中的下一个环节
Chain.prototype.setNextSuccessor = function (successor) {
return this.successor = successor
}
// 传递请求给下一个节点
Chain.prototype.passRequest = function () {
const ret = this.fn.apply(this, arguments)
if (ret === 'nextSuccessor') {
return this.successor && this.successor.passRequest.apply(this.successor, arguments)
}
return ret
}
const chinaOrder500 = new Chain(order500);
const chainOrder200 = new Chain(order200);
const chainOrderNormal = new Chain(orderNormal)
// chinaOrder500.setNextSuccessor(chainOrder200);
// chainOrder200.setNextSuccessor(chainOrderNormal);
chinaOrder500.setNextSuccessor(chainOrder200).setNextSuccessor(chainOrderNormal)
chinaOrder500.passRequest(1, true, 500);
chinaOrder500.passRequest(2, true, 500);
chinaOrder500.passRequest(3, true, 500);
chinaOrder500.passRequest(1, false, 0);
小C将自己的代码提交给主管,主管感觉写的停不错。业务与代码解耦了,链接灵活性高。
JavaScript有它天然的独特性,我们可以利用高阶函数的思想也能实现上面的业务。
/***
** orderType 表示订单类型
** pay 表示用户是否已经支付定金
** stock 表示普通购买的手机库存数量
*/
const order500 = function (orderType, pay, stock) {
if (orderType === 1 && pay === true) {
console.log('500元定金预购,得到100元代金券')
} else {
return 'nextSuccessor'
}
}
const order200 = function (orderType, pay, stock) {
if (orderType === 2 && pay === true) {
console.log('200元定金购买,得到50元代金券')
} else {
return 'nextSuccessor'
}
}
const orderNormal = function (orderType, pay, stock) {
if (stock > 0) {
console.log('普通购买,无优惠卷')
} else {
console.log('手机库存不足')
}
}
Function.prototype.after = function (fn) {
const self = this;
return function () {
const ret = self.apply(this, arguments);
if (ret === 'nextSuccessor') {
return fn.apply(this, arguments)
}
return ret;
}
}
const order = order500.after(order200).after(orderNormal);
order(1, true, 500)
order(2, true, 500)
order(1, false, 500)
我们还可以实现异步的职责链
//测试结果
const Chain = function (fn) {
this.fn = fn;
this.successor = null;
}
Chain.prototype.setNextSuccessor = function (successor) {
return this.successor = successor
}
Chain.prototype.passRequest = function () {
const ret = this.fn.apply(this, arguments)
if (ret === 'nextSuccessor') {
return this.successor && this.successor.passRequest.apply(this.successor, arguments)
}
return ret
}
// 异步的职责链
Chain.prototype.next = function () {
return this.successor && this.successor.passRequest.apply(this.successor, arguments)
}
const fn1 = new Chain(function () {
console.log(1)
return 'nextSuccessor'
})
const fn2 = new Chain(function () {
console.log(2)
const self = this
setTimeout(() => {
self.next()
}, 1000)
})
const fn3 = new Chain(function () {
console.log(3)
})
// 链式调用
fn1.setNextSuccessor(fn2).setNextSuccessor(fn3);
fn1.passRequest()