专业编程基础技术教程

网站首页 > 基础教程 正文

不到30行代码,有5层嵌套的if语句?避免陷入“if-else地狱”!

ccvgpt 2024-11-20 13:02:16 基础教程 8 ℃

【CSDN 编者按】随着应用程序复杂度的日益增长,传统编程模式下层层嵌套的 if-else 语句逐渐成为了开发者们的“梦魇”,不仅令逻辑变得晦涩难懂,更增加了后期调试与维护的成本。面对这一挑战,本文作者认为函数式编程风格以其独特的魅力,提供了一条避免陷入“if-else 地狱”的优雅路径。

不到30行代码,有5层嵌套的if语句?避免陷入“if-else地狱”!

原文链接:https://lackofimagination.org/2024/09/avoiding-if-else-hell-the-functional-style/

作者 | Aycan Gulez 翻译 | 郑丽媛
出品 | CSDN(ID:CSDNnews)

多年前,我参与了一个至今仍被广泛使用的打车移动应用的开发。我不知道现在他们运行的代码是什么情况,但如果我没记错的话,早期关于司机分配这部分的代码,很大程度上类似于下面这个极度简化的示例:

async function assignDriver(rider, availableDrivers) { const driverDistances = await calculateDistances(rider.location, availableDrivers); let assignedDriver = ;
for (let driver of availableDrivers) { if (driverDistances[driver.id] <= 5) { if (!rider.preferredVehicle || rider.preferredVehicle === driver.vehicle) { if (driver.rating >= 4.5) { if (rider.preferences.includes('Premium Driver')) { if (driver.isPremiumDriver) { assignedDriver = driver; break; } else { continue; } } else { assignedDriver = driver; break; } } else if (driver.rating >= 4.0) { assignedDriver = driver; break; } } } }
return assignedDriver;}

在这段不到 30 行的代码中,有五层嵌套的 if 语句。也许有人会说,这看起来还不算太糟,但不难想象,如果再加上诸如高峰期加价、忠诚度计划等更多检查条件,这些代码会变得多么复杂。

幸运的是,我们有办法将代码扁平化处理,而最终的结果可能会让你大吃一惊:当我们完成重构后,就不会再有 if 语句了。


利用保护子句

让我们先从简单的开始。第一个 if 语句用于检查司机和乘客之间允许的最大距离,由于它适用于所有情况,因此可以将其转换为保护子句,从而移除一层嵌套。同样,我们还可以为首选车辆检查添加另一个保护子句,以去除另一层嵌套。由此修改后的代码如下所示:

async function assignDriver(rider, availableDrivers) { const driverDistances = await calculateDistances(rider.location, availableDrivers); let assignedDriver = ;
for (let driver of availableDrivers) { if (driverDistances[driver.id] > 5) { continue; } if (rider.preferredVehicle && rider.preferredVehicle !== driver.vehicle) { continue; } if (driver.rating >= 4.5) { if (rider.preferences.includes('Premium Driver')) { if (driver.isPremiumDriver) { assignedDriver = driver; break; } else { continue; } } else { assignedDriver = driver; break; } } else if (driver.rating >= 4.0) { assignedDriver = driver; break; } }
return assignedDriver;}


决策表

与其在函数内部硬编码逻辑,我们可以将每个 if-else 模块放在它自己的函数中,并将这些函数放入一个数组,形成一个决策表。然后,我们遍历决策表中的每个函数,直到得到一个肯定的响应。当然了,表中的条目必须从最具体的到最不具体的顺序排列,这样才能在我们的案例中正常运行。

const conditions = [ (rider, driver) => driver.rating >= 4.5 && rider.preferences.includes('Premium Driver') && driver.isPremiumDriver, (rider, driver) => driver.rating >= 4.5 && !rider.preferences.includes('Premium Driver'), (rider, driver) => driver.rating >= 4.0 && driver.rating < 4.5,];
async function assignDriver(rider, availableDrivers, conditions) { const driverDistances = await calculateDistances(rider.location, availableDrivers); let assignedDriver = ;
for (let driver of availableDrivers) { if (driverDistances[driver.id] > 5) { continue; } if (rider.preferredVehicle && rider.preferredVehicle !== driver.vehicle) { continue; } if (conditions.find((condition) => condition(rider, driver))) { assignedDriver = driver; break; } }
return assignedDriver;}

有了决策表,我们就彻底消除了嵌套的 if 语句,还有一个额外的好处:现在只需简单编辑条件数组,就可以更改驱动程序的赋值逻辑。


函数组合

让我们把 for 循环转换为 Array.find(),并为循环中的每个 if 语句创建单独的函数,从而消除剩余的 if 语句:

const conditions = [ (rider, driver) => driver.rating >= 4.5 && rider.preferences.includes('Premium Driver') && driver.isPremiumDriver, (rider, driver) => driver.rating >= 4.5 && !rider.preferences.includes('Premium Driver'), (rider, driver) => driver.rating >= 4.0 && driver.rating < 4.5,];
async function assignDriver(rider, availableDrivers, conditions) { const driverDistances = await calculateDistances(rider.location, availableDrivers);
const isDriverClose = (driver) => driverDistances[driver.id] <= 5; const isVehicleOK = (rider, driver) => !rider.preferredVehicle || rider.preferredVehicle === driver.vehicle; const isAConditionSatisfied = (rider, driver) => conditions.find((condition) => condition(rider, driver));
const assignedDriver = availableDrivers.find( (driver) => isDriverClose(driver) && isVehicleOK(rider, driver) && isAConditionSatisfied(rider, driver) );
return assignedDriver || ;}

总结

通过利用基本的函数式编程原则,我们已经:

● 移除了所有的嵌套 if 语句,

● 将大部分逻辑解耦,使其易于修改,

● 通过将各个 if-else 块放入其自己的函数中,使代码更易于理解,

● 最后还有个额外的好处,即程序大小减少了三分之一。

最近发表
标签列表