现有业务中,存在大量复杂的判断,如弹窗逻辑,内部有一系列复杂的if判断,不同弹窗之间存在优先级,当上级弹窗符合条件时代码判断终止,否则继续向下级判断。

1
2
3
4
5
6
7
8
9
10
11
12
13
function modal (option) {
// 追偿
if (isRecovery === '0' || isRecovery === '2') {
...
return
}
// 未授权
if (...) {
...
return
}
...
}

这里的函数过大,且不同逻辑都在一起,一方面看着不是很清晰直观,一方面不利于将来的维护,比如调整弹窗优先级等等。可以引入责任链模式进行优化。

责任链模式

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

先给Function原型绑定一个after函数,用于在两个函数之间生成责任链。并定义一个标识’nextSuccessor’,前往下一级责任链。

1
2
3
4
5
6
7
8
9
10
Function.prototype.after = function(fn) {
var self = this;
return function() {
var ret = self.apply(this, arguments);
if(ret === "nextSuccessor") {
return fn.apply(this, arguments);
}
return ret;
};
}

下面对弹窗代码进行改造:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 追偿弹窗
const recoveryModal = (option) => {
if (isRecovery === '0' || isRecovery === '2') {
...
return
}
return 'nextSuccessor'
}
// 授权弹窗
const authModal = (option) => {
if (...) {
...
return
}
return 'nextSuccessor'
}
...

const modal = recoveryModal
.after(authModal)
.after(...)
modal(option)

可以看到,原先的弹窗函数拆分成了一个个小函数,这些代码的顺序都无所谓,在最后写modal函数,控制好责任链的顺序,再调用就可以了。既清晰,又易维护,可以方便的调整弹窗的优先级顺序。

这里我进一步将责任链编写用一个函数传入数组来实现:

1
2
3
4
5
6
7
8
9
// 数组转责任链(责任链after函数见polyfill)
export const arr2ChainOfResponsibility = (fnArr = []) => {
if (fnArr.length === 0) return () => {}

// 遍历绑定责任链, 前一项返回'nextSuccessor'去下一项
return fnArr.reduce((a, b) => {
return a.after(b)
})
}

后面的modal改造一下:

1
2
3
4
5
6
const modal = arr2ChainOfResponsibility([
recoveryModal,
authModal,
...,
])
modal(option)