13. 简化条件逻辑(一):分解条件表达式、合并条件表达式、以卫语句取代嵌套条件表达式

条件逻辑,说白了就是代码里的「岔路口」。

我见过太多项目,代码读起来像迷宫——一个 if 套一个 if,再套一个 else if,最后连写代码的人自己都绕晕了。今天咱们聊聊三个最常用的简化手法:分解条件表达式合并条件表达式以卫语句取代嵌套条件表达式

核心原则:条件逻辑应该像高速公路,而不是乡间小道。每个分支都清晰可见,没有隐藏的弯道。

简化条件逻辑三大手法 条件逻辑重构 分解条件表达式 把大条件拆成小函数 合并条件表达式 相同结果的条件合并 卫语句取代嵌套 提前返回,消除嵌套 适用场景 • 条件逻辑超过3层嵌套 • 条件表达式超过20个字符 • 多个条件分支执行相同逻辑 • 条件中有大量 && 或 || 连接

一、分解条件表达式:把大块头拆成小零件

先看一段代码。你感受一下:

// 重构前
if (date.after(plan.summerStart) && date.before(plan.summerEnd)) {
  charge = quantity * plan.summerRate;
} else {
  charge = quantity * plan.regularRate + plan.regularServiceCharge;
}

这段代码其实不难,但每次读都要在脑子里过一遍「夏天是什么时候?夏天费率是多少?冬天又是什么规则?」。说白了,条件本身和分支逻辑混在一起了。

我个人习惯的做法是:把条件判断抽成函数,把每个分支的计算也抽成函数

// 重构后
if (isSummer(date, plan)) {
  charge = summerCharge(quantity, plan);
} else {
  charge = regularCharge(quantity, plan);
}

function isSummer(date, plan) {
  return date.after(plan.summerStart) && date.before(plan.summerEnd);
}

function summerCharge(quantity, plan) {
  return quantity * plan.summerRate;
}

function regularCharge(quantity, plan) {
  return quantity * plan.regularRate + plan.regularServiceCharge;
}

我的经验:我在重构一个支付系统时遇到过类似情况。原来的条件判断写了整整 30 行,里面还嵌套了三个 if。拆成 5 个小函数后,代码行数没少多少,但可读性翻了三倍。后来新同事接手,看一遍就懂了。

你想想看,拆完之后主流程变成了什么?就是一句「如果是夏天,算夏天费用;否则算普通费用」。这不就是业务人员嘴里说出来的话吗?

二、合并条件表达式:别写重复的「如果」

有时候我们会遇到这种情况:多个不同的条件,最终执行的是同一段逻辑

// 重构前
if (age < 18) {
  return "未成年人禁止购买";
}
if (isBlacklisted(user)) {
  return "未成年人禁止购买";
}
if (orderAmount > 10000 && !user.isVerified) {
  return "未成年人禁止购买";
}

嗯,这里要注意——三个条件都返回同一个字符串。但代码却写了三遍。读代码的人会想:「这三个条件有什么不同?为什么分开写?」

合并之后,逻辑就清晰了:

// 重构后
if (isUnderage(age) || isBlacklisted(user) || isHighRiskOrder(user, orderAmount)) {
  return "未成年人禁止购买";
}

function isUnderage(age) {
  return age < 18;
}

function isBlacklisted(user) {
  return user.status === 'BLACKLISTED';
}

function isHighRiskOrder(user, orderAmount) {
  return orderAmount > 10000 && !user.isVerified;
}

避坑指南:我曾经犯过一个错误——把条件合并得太狠。比如把「用户是VIP」和「订单金额大于1000」合并成一个条件,但后来业务改了,VIP用户要单独处理。结果又得拆开。所以合并前先想清楚:这些条件在业务上是不是真的「同一种情况」?

合并条件表达式的核心原则就一条:结果相同,条件合并;结果不同,条件分开

三、以卫语句取代嵌套条件表达式:提前说「不」

这是我最喜欢的手法。很多新手写代码喜欢这样:

// 重构前
function getPayAmount(employee) {
  let result;
  if (employee.isRetired) {
    result = 0;
  } else {
    if (employee.years > 10) {
      result = employee.salary * 1.5;
    } else {
      result = employee.salary * 1.2;
    }
  }
  return result;
}

你看,这里有一个 if-else 套着另一个 if-else。读代码的时候,你的脑子要同时记住外层条件和内层条件。累不累?

用卫语句改写:

// 重构后
function getPayAmount(employee) {
  if (employee.isRetired) {
    return 0;  // 卫语句:特殊情况提前返回
  }
  
  if (employee.years > 10) {
    return employee.salary * 1.5;
  }
  
  return employee.salary * 1.2;
}

差别在哪?卫语句把「特殊情况」提前处理掉,剩下的就是正常流程。你想想看,读代码的时候,看到 if (isRetired) return 0,你马上就知道「哦,退休的人直接拿0,不用往下看了」。

什么时候用卫语句?一个简单的判断标准:如果某个条件分支是「异常情况」或「边界情况」,就用卫语句提前返回。如果所有分支都是「正常流程」,那用 if-else 也没问题。

四、三种手法的对比与选择

手法 适用场景 核心收益 注意事项
分解条件表达式 条件判断复杂,或分支逻辑较长 提升可读性,让条件「自解释」 不要过度拆分,每个函数只做一件事
合并条件表达式 多个条件执行相同逻辑 消除重复,减少分支数量 确认业务上确实是「同一类情况」
卫语句取代嵌套 嵌套超过两层,有明确的「特殊情况」 减少嵌套深度,突出正常流程 不要把所有条件都写成卫语句

这三种手法不是互斥的。我在实际项目中经常组合使用:先用卫语句把异常情况提前返回,再把剩下的条件拆成小函数,最后看看有没有可以合并的条件。

一个小技巧:重构条件逻辑时,先画一个「条件分支图」。把每个条件、每个分支的结果画出来。这样你一眼就能看出哪些可以合并、哪些可以提前返回。我每次重构复杂条件逻辑前都会画这个图,比直接改代码靠谱多了。

最后说一句:条件逻辑重构的目标不是「消灭 if」,而是「让 if 变得好读」。好的条件逻辑,读起来就像在讲故事——先处理异常,再处理正常情况,每个分支都清晰明了。


公众号:蓝海资料掘金营,微信deep3321