第六部分导读:简化条件逻辑
条件逻辑是程序里最难读的部分。一行赋值只有一条路,一个 if 就有两条,三个 if 套在一起,读者脑子里要同时装着八种可能。更麻烦的是,条件往往同时承担两件事:判断“现在是什么情况”,和决定“这种情况下做什么”。if day >= start and day <= end 这一行,读的人要先翻译成“是不是夏季”,才能接着读下面的算式;嵌套到第三层的正常流程,要先读完所有例外才找得到;同一个 match bird.type 抄在五个函数里,加一种鸟就要改五处,漏一处不会报错,只会在某张卡片上显示“未知”;同一句 if customer == "unknown" 散在几十个调用方,新人漏写一句就是线上的空指针。这一部分的六个手法分别对付这些情况:给条件和分支起名字,把结果相同的条件合并,让例外先返回,把按类型的分支交给多态,用特例对象吸收到处出现的空值检查,以及把代码默默依赖的假设写成断言。它们的共同目标是让条件语句读起来像需求文档里的规则原文。
| 手法 | 一句话 | 流行度 | 档 |
|---|---|---|---|
| 分解条件表达式(第 35 章) | 把条件和每个分支各提成有名字的函数 | ★★★ | 完整 |
| 合并条件表达式(第 36 章) | 把结果相同的几个条件合成一个,再起名 | ★★ | 精简 |
| 以卫语句取代嵌套条件表达式(第 37 章) | 特殊情况先检查、先返回,正常流程不缩进 | ★★★ | 完整 |
| 以多态取代条件表达式(第 38 章) | 按类型的分支改成每种类型一个子类 | ★★★ | 完整 |
| 引入特例(第 39 章) | 用一个特例对象替掉到处出现的同一种特殊值检查 | ★★ | 完整 |
| 引入断言(第 40 章) | 把代码依赖的假设写成断言 | ★ | 速览 |
闻到什么味道先看哪一章:
- 过长函数,一个 if 的条件是一串比较、分支是一堆算式,要读三遍才知道在说什么 → 第 35 章 分解条件表达式。
- 重复代码,几个 if 各自返回同一个值,其实是同一条规则 → 第 36 章 合并条件表达式。
- 过长函数,if 套 if 套 if,正常流程埋在最深一层 → 第 37 章 以卫语句取代嵌套条件表达式。
- 重复的 switch,同一个按类型的 switch 或 match 出现在好几个函数里 → 第 38 章 以多态取代条件表达式。
- 重复代码,到处都在写
if x is None或if customer == "unknown",而且应对都一样 → 第 39 章 引入特例。