前端日常开发中,经常会遇到一些特别繁琐冗余业务代码,特别是在维护旧项目时遇到复杂的业务逻辑嵌套在深层的 if-else
语句中就更多了。如果你是简单地增量修改不仅不会改变它的复杂性,反而会增加复杂性和降低可读性。接下来在这里给大家分享三种简单而常见的重构方法。
意大利面条代码
“意大利面条代码”指的是在处理复杂业务过程时很常见的一种现象,它通常具有以下特点:
- 内容冗长
- 结构混乱
- 嵌套深
我们知道,主流编程语言都有函数或方法来组织代码。而对于意大利面条代码,我们可以将其视为满足这些特点的函数。根据语言语义的不同,可以将其分为两种基本类型:
if…if 类型
这种代码结构看起来像这样:
function demo(a, b, c) { if (f(a, b, c)) { if (g(a, b, c)) { // ... } // ... if (h(a, b, c)) { // ... } } if (j(a, b, c)) { // ... } if (k(a, b, c)) { // ... } }
流程图如下:
在代码实现中,我们可以通过责任链数组定义等价于 else if
的规则。
const rules = [ { match: function (a, b, c) { /* ... */ }, action: function (a, b, c) { /* ... */ } }, { match: function (a, b, c) { /* ... */ }, action: function (a, b, c) { /* ... */ } }, { match: function (a, b, c) { /* ... */ }, action: function (a, b, c) { /* ... */ } } // ... ]
rules
中的每项都具有 match
和 action
属性。此时我们可以将原来的 else if
函数重写为遍历责任链数组:
function demo (a, b, c) { for (let i = 0; i < rules.length; i++) { if (rules[i].match(a, b, c)) { return rules[i].action(a, b, c) } } }
当每个责任被匹配时,原函数将直接返回,这也完全符合 else if 的语义。这样,我们实现了将复杂的 else if 逻辑拆分为单独的部分。
结语
面条代码往往出现在无脑的“粗暴、快速、猛烈”风格的开发中。许多 bug 修复是通过粗暴地在这里添加一个 if 并在多处返回语句来完成的,再加上缺乏注释,这很容易导致代码可读性降低和复杂性增加。
然而,解决这个问题其实并不复杂。这些示例之所以简单,基本上是因为强大的高级编程