嗨,大家好!这里是道长王jj
~ 🎩🧙♂️
日常的代码审查工作总是会带来各种惊喜🎁,尤其当你遇到那些让你眼前一黑的代码。
比如我在上次的审查中,看到我们的小明同事在他的JavaScript代码中堆砌了一个看起来就像一座大山的超过20个的 if...else 语句。类似下面这样:
function calculatePrice(type, basePrice) {
if (type === 'student') {
return basePrice * 0.8;
} else if (type === 'senior') {
return basePrice * 0.7;
} else if (type === 'veteran') {
return basePrice * 0.75;
}
// 这个列表有20多个条件,我们在这里省略...
else {
return basePrice;
}
}
🙅♂️ 为何不推荐大量的 if...else
咳咳,看到这里,让我想起了小时候堆积木游戏,每堆一个积木都充满了危险和快感。但这样的代码确实存在一些问题,比如:
- 阅读困难:就像尝试阅读一篇只有一个长长的段落的小说,你需要花费大量的时间和精力去理解它。
- 高维护成本:想象一下,如果需要在中间插入一个新的条件,你需要找到正确的位置,然后小心翼翼地插入新的 if...else 语句。
- 可扩展性差:对于特殊的需求,例如动态的添加新的折扣类型,你可能需要大量的修改和测试。
作为一名合格的开发者,我们总是希望自己能写出优雅、可读性高、易维护的代码。于是,让我们看看有没有其他方法能替代这个冗长的 if...else 呢?😉
❗注意!不是说所有的if…else都要被替代
重构代码的目的是为了提高代码的可读性、可维护性和扩展性。
但并不是所有的if...else语句都应该被替代或重构!
如果你的代码里是以下的情况,就不要想着重构炫技啦!
- 简单的条件分支:如果代码中的if...else语句仅有一到两个简单的条件分支,没必要改。
- 高度相关的逻辑分支:复杂的逻辑,如果被分解成多个独立的函数或对象,会失去逻辑的连贯性和上下文含义,你也不想代码看不懂吧!
👏 项目案例:函数式编程+设计模式替代 if...else
注意:以下的代码都有意地在使用JavaScript的对象字面量,可以使代码更加干净和易于阅读。这是一种函数式编程的方式。
设计模式是为了解决一些特定问题而提出的代码结构,它能帮助我们更好地组织代码,提高代码的可读性和可维护性。按照水文掘金老套路。我先介绍一下有哪几种常见的设计模式可以优化这类问题。
策略模式
策略模式定义了一系列的算法,并将每一个算法封装起来,使它们可以互相替换。在 JavaScript 中,我们可以使用对象来实现策略模式,这也是最简单的改造,就像下面这样:
const strategies = {
'student': (basePrice) => {
return basePrice * 0.8;
},
'senior': (basePrice) => {
return basePrice * 0.7;
},
'veteran': (basePrice) => {
return basePrice * 0.75;
},
'default': (basePrice) => {
return basePrice;
}
}
const calculatePrice = (type, basePrice) => {
return (strategies[type] || strategies['default'])(basePrice);
}
calculatePrice('student', 1) // 输出: 0.8
❓如果是面对多层嵌套呢?
对于多层嵌套的if...else,我们同样可以通过使用策略模式来改善代码的可读性和维护性。只是说我们把判断逻辑放在了独立的函数中。
假设我们现在有一个需求,即根据用户的类型和他们的购买量来计算折扣。如果用户是学生,购买量大于10个,他们可以享受8折优惠;如果用户是老年人,购买量大于20个,他们可以享受7折优惠。
const strategies = {
'student': quantity => quantity > 10 ? 0.8 : 1,
'senior': quantity => quantity > 20 ? 0.7 : 1,
'default': () => 1
};
const calculate = (type, quantity) => {
return (strategies[type] || strategies['default'])(quantity)
}
calculate('student', 15) // 输出: 0.8
这样一来,我们的代码就变得更加清晰和易读了。而且如果我们想添加新的策略,只需要在 strategies
对象中添加新的属性和函数就可以了。
工厂模式
其实这个我都有点不愿意讲了,因为上一个例子中其实本身也是一种工厂模式的实现,这一次我们要把那个例子转换为一个更明显的工厂模式,我们可以将函数calculate
转换为一个工厂函数,它创建并返回一个对象,这个对象有一个calculate
方法:
const strategies = {
'student': quantity => quantity > 10 ? 0.8 : 1,
'senior': quantity => quantity > 20 ? 0.7 : 1,
'default': () => 1
};
const createCalculator = (type) => {
return {
calculate: (quantity) => (strategies[type] || strategies['default'])(quantity)
}
}
const studentCalculator = createCalculator('student');
studentCalculator.calculate(15); // 输出: 0.8
查找表模式
查找表模式其实是策略模式的一种简化形式,它更像是一个简单的映射表。我们可以把所有的策略映射到一个对象中,然后通过键来查找对应的策略。对于上面的例子而言,本质只是改变了存储方式,我们使用映射表来保存策略就行了(是不是突然觉得也没有那么高大上了哈哈😄):
const studentStrategy = quantity => quantity > 10 ? 0.8 : 1;
const seniorStrategy = quantity => quantity > 20 ? 0.7 : 1;
const defaultStrategy = () => 1;
const strategies = {
'student': studentStrategy,
'senior': seniorStrategy,
'default': defaultStrategy
};
const calculate = (type, quantity) => {
return (strategies[type] || strategies['default'])(quantity)
}
calculate('student', 15); // 输出: 0.8
职责链模式
职责链模式是一种对象的行为模式,在这种模式中,每一个对象都有机会处理请求,从而解除了发送者和接收者之间的耦合关系。在JavaScript中,我们可以用链式调用来实现职责链模式:
// 学生条件进入
const studentHandler = (type, quantity, next) => {
if (type === 'student' && quantity > 10) {
return 0.8;
}
return next(type, quantity);
};
// 军人条件进入
const seniorHandler = (type, quantity, next) => {
if (type === 'senior' && quantity > 20) {
return 0.7;
}
return next(type, quantity);
};
// 没有特殊条件时进入
const defaultHandler = (type, quantity, next) => {
return 1;
};
// 定义一个函数,这个函数会生成一个处理器链
const createHandlerChain = (...handlers) => (type, quantity) => {
let index = 0;
const next = (type, quantity) => {
if (index < handlers.length) {
return handlers[index++](type, quantity, next);
}
};
return next(type, quantity);
};
// 组合函数
const calculate = createHandlerChain(studentHandler, seniorHandler, defaultHandler);
calculate('student', 15)
; // 输出: 0.8
各类设计模式和最佳实践能运用到实际项目中(复制粘贴,嘿嘿),对我们一定有不小地进步!
🎉 希望本文能够帮助你解决优化大量的 if...else 语句的问题。如果你有任何疑问或者想进一步讨论相关话题,请随时告诉我。🚀✨