“这是我参与8月更文挑战的第20天,活动详情查看:8月更文挑战”
前言
在面试高级前端时,往往会遇到一些关于设计模式的问题,每次都回答不太理想。恰逢8月更文挑战的活动,准备用一个月时间好好理一下关于设计模式方面的知识点,给自己增加点面试的底气。
在 上一篇简单实现了一个职责链模式,但是其中职责的传递非常僵硬,且违背了开放-封闭原则,故本文来介绍一种一种灵活可拆分的职责链节点的实现。
解耦
先来看一下之前设计的职责链节点。
// 预缴1000定金
const order1000 = (orderType, pay, stock) => {
if (orderType === 1 && pay === true) {
console.log('1000 元定金预购, 得到 500 优惠券');
} else {
order500(orderType, pay, stock); // 将请求传递给预缴1000定金订单
}
};
// 预缴500定金
const order500 = (orderType, pay, stock) =>{
if (orderType === 2 && pay === true) {
console.log('500 元定金预购, 得到 200 优惠券');
} else {
orderNormal(orderType, pay, stock); // 将请求传递给普通订单
}
};
// 普通购买订单
const orderNormal = (orderType, pay, stock) =>{
if (stock > 0) {
console.log('普通购买, 无优惠券');
} else {
console.log('手机库存不足');
}
};
先将其解耦,怎么解耦呢,要做个约定,如果某个节点不能处理请求,则返回一个特定的字符串 toNextNode
来表示该请求需要继续往后面的节点传递。
// 预缴1000定金
const order1000 = (orderType, pay, stock) => {
if (orderType === 1 && pay === true) {
console.log('1000 元定金预购, 得到 500 优惠券');
} else {
return 'toNextNode'; // 我不知道下一个节点是谁,反正把请求往后面传递
}
};
// 预缴500定金
const order500 = (orderType, pay, stock) =>{
if (orderType === 2 && pay === true) {
console.log('500 元定金预购, 得到 200 优惠券');
} else {
return 'toNextNode'; // 我不知道下一个节点是谁,反正把请求往后面传递
}
};
// 普通购买订单
const orderNormal = (orderType, pay, stock) =>{
if (stock > 0) {
console.log('普通购买, 无优惠券');
} else {
console.log('手机库存不足');
}
};
组装职责链
经过解耦,上面的每个函数都变成一个个普通函数,这里要创建一个包装函数来把普通函数包装成职责链节点。
用一个类来作为包装函数,类中有方法,用来设置下个请求节点,还得有一个方法用来执行当前节点,且执行完后,若请求无法被处理,继续请求下个节点。
class Chain{
constructor(fn){
this.fn = fn;
this.nextNode = null;
}
setNextNode(fn){
return this.nextNode = fn;
}
passRequest(){
const res = this.fn.apply(this,arguments);
if(res === 'toNextNode'){
return this.nextNode && this.nextNode.passRequest.apply(this.nextNode, arguments);
}
return res;
}
}
其中setNextNode
方法设置下个请求节点,passRequest
方法用来执行当前节点,且执行完后,若请求无法被处理,继续请求下个节点。
现在把之前的三个函数包装成职责链节点:
const chainOrder1000 = new Chain(order1000);
const chainOrder500 = new Chain(order500);
const chainOrderNormal = new Chain( orderNormal);
然后组装职责链节点成一条职责链:
chainOrder1000.setNextNode( chainOrder500 );
chainOrder500.setNextNode( chainOrderNormal );
最后开始执行职责链:
chainOrder1000.passRequest( 1, true, 500 ); // 输出:1000 元定金预购,得到 500 优惠券
chainOrder1000.passRequest( 2, true, 500 ); // 输出:500 元定金预购,得到 200 优惠券
chainOrder1000.passRequest( 3, true, 500 ); // 输出:普通购买,无优惠券
chainOrder1000.passRequest( 1, false, 0 ); // 输出:手机库存不足
拆卸职责链重新组装
比如现在要新增一种的营销策略换成预缴300元定金,得50优惠券。可以这么处理。
// 预缴300定金
const order300 = (orderType, pay, stock) =>{
if (orderType === 4 && pay === true) {
console.log('300 元定金预购, 得到 50 优惠券');
} else {
return 'toNextNode'; // 我不知道下一个节点是谁,反正把请求往后面传递
}
};
chainOrder300= new Chain(order300);
chainOrder1000.setNextSuccessor(chainOrder500);
chainOrder500.setNextSuccessor(chainOrder300);
chainOrder300.setNextSuccessor(chainOrderNormal);
chainOrder1000.passRequest( 4, true, 500 );// 输出:300 元定金预购,得到 50 优惠券
这样实现职责链,其职责链节点可以灵活拆卸。在变更职责链中节点顺序或新增职责链节点时,不会修改职责链节点的内容,遵循开放-封闭原则。
异步的职责链节点如何实现
上面介绍的职责链节点中都是同步返回一个特定的字符串 toNextNode
来表示该请求需要继续往后面的节点传递。那如果职责链节点的请求是异步的呢,等异步请求返回的结果才能决定是否继续请求下一个职责链节点。那要如何实现?留个思考题,将在下篇文章中介绍。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!