Remove Flag Argument 是什么
用布尔参数表示两种不同行为的函数,拆成两个命名函数:调用点自解释,函数内的分支消失。标志参数的代价体现在阅读端——deliveryDate(order, true) 的 true 是什么含义,只能靠记忆或跳进函数体才知道。拆分成本通常很低,收益直接落在可读性上。
基本信息
| 场景 | book(customer, true) 之类的调用 |
|---|---|
| 做法 | 拆成 book() / bookExpress() 两个入口 |
| 收益 | 调用语义在函数名上自明,内部分支消失 |
| 边界 | 参数表示数据而非行为时保留原样 |
识别与拆分
- 调用点需要看函数实现才能理解 true 的含义
- 函数体内最外层就是一个 if (flag) 分成两条路径
- 同一个布尔值在多个调用点的取值固定不变:调用点其实已经是两种用途
- 参数在函数体内被反复使用,两条件分支几乎不共享代码
- 参数是数据而非行为(例如 enableCache 配置项由外部配置决定)时不要拆
- 拆分时保留一个内部方法承接公共部分,避免代码重复
Java 示例
Java 示例
// 之前:true 是什么含义?只能跳进去看
Date d = deliveryDate(order, true);
Date d2 = deliveryDate(order, false);
// 之后:调用点自解释
Date d = expeditedDeliveryDate(order);
Date d2 = regularDeliveryDate(order);
// 共同部分留在私有方法里,避免重复
private Date deliveryDate(Order o, DeliveryMode mode) { /* ... */ }该拆与不该拆
| 情况 | 处理 | 理由 |
|---|---|---|
| 布尔值决定两套行为 | 拆成两个函数 | 调用语义自明 |
| 布尔值来自配置或用户输入 | 保留参数 | 它是数据,不是行为 |
| 枚举区分三种以上行为 | 按取值拆成多个入口 | 避免调用方记取值含义 |
| 参数仅作为内部透传 | 一层层清理 | 透传的标志位最难追踪 |
拆出的函数名必须体现差异:expressDeliveryDate 与 deliveryDate 这种命名让人猜不出区别,等于只把问题挪到函数名上。名字里应带上区分行为的词,例如 expedited、draft、dryRun。
过度拆分会带来重复:两个入口如果 90% 逻辑相同,应把公共部分留在私有方法里,由两个入口各自决定差异部分,而不是复制整段实现。