第七部分导读:重构 API
函数的内部写得再好,调用方看到的只有它对外的样子:名字、参数、返回值,以及调用它会不会顺手改掉什么。这一部分的手法都在处理这个外观。外观不好,代价落在每一个调用处:调用处写着 delivery_date(order, True),读的人得跳进函数里才知道 True 是加急;调用方先从房间对象里取出最低温和最高温再分别传进去,函数要多看一个字段,所有调用方都得跟着改;一个查名单的函数顺手拉响了警报,于是谁都不敢为了“看一眼”去调用它。
判断标准有两条。第一,调用处读起来是否就是它要做的事,不需要跳进函数体去核对。第二,函数要的数据变了,或者行为分了叉,改动是否只落在函数内部,而不是摊到每个调用方。第 6 章的改变函数声明是这一部分所有手法的基础工具,本部分的大多数手法,最后一步都是一次迁移式的改声明。
| 手法 | 一句话 | 流行度 | 档 |
|---|---|---|---|
| 将查询函数和修改函数分离(第 42 章) | 返回值的函数不改状态 | ★★★ | 完整 |
| 函数参数化(第 43 章) | 几个只差一个值的函数合成一个 | ★★ | 精简 |
| 移除标记参数(第 44 章) | 用两个有名字的函数替掉布尔开关 | ★★★ | 完整 |
| 保持对象完整(第 45 章) | 传整个对象,而不是从它身上拆出来的几个值 | ★★ | 精简 |
| 以查询取代参数 / 以参数取代查询(第 46 章) | 函数自己能算的值不要传;外部状态改成参数传进来 | ★★ | 精简 |
| 移除设值函数(第 47 章) | 创建后不该变的字段不提供修改方法 | ★ | 速览 |
| 以工厂函数取代构造函数(第 48 章) | 用有名字的函数创建对象 | ★★ | 精简 |
| 以命令取代函数 / 以函数取代命令(第 49 章) | 拆不动的长函数变成对象;没用上对象能力的命令变回函数 | ★★ / ★ | 精简 |
闻到什么味道先看哪一章:
- 可变数据,一个返回结果的函数顺手改了共享状态 → 第 42 章 将查询函数和修改函数分离;字段只该在创建时设一次 → 第 47 章 移除设值函数。
- 过长参数列表,调用处写着
f(x, True)→ 第 44 章 移除标记参数;参数是从同一个对象里拆出来的 → 第 45 章 保持对象完整;参数能由函数自己算出 → 第 46 章 以查询取代参数。 - 重复代码,几个函数只差几个字面量 → 第 43 章 函数参数化。
- 全局数据,函数内部读了全局变量,测试要先摆弄它 → 第 46 章 以参数取代查询。
- 过长函数,局部变量缠在一起、提炼函数拆不动 → 第 49 章 以命令取代函数。