首页/开发/代码质量与评审速查/坏味道:发散式变化(Divergent Change)
重构手法62 条

坏味道:发散式变化(Divergent Change)

一个类因不同原因被反复修改(数据库字段变了改它、税费规则变了也改它):按变化原因拆分,用 Split Phase、Extract Class 让每种变化只影响一个模块。

什么是发散式变化

发散式变化指同一个类因为多种不相关的原因被反复修改:数据库字段变了改它,税费规则变了也改它。它与霰弹式修改互为镜像——那里是一个原因要改很多地方,这里是多个原因挤在一个地方。处方是按变化原因拆分,让每一类变化只影响一个模块。

基本信息

典型信号同一文件出现在差异很大的多类需求中
处方提取类、拆分阶段
目标一个模块只对一类变化负责
反向对照霰弹式修改:一个变化要改很多地方
判断依据这两类修改为什么会撞在同一个文件里

典型使用场景

  • 一个服务类同时负责参数校验、定价计算与数据写入
  • 报表类既管取数逻辑又管排版输出
  • 定时任务里混着业务规则与通知发送
  • 实体类同时承担持久化映射与业务行为
  • 控制器里混入权限判断与响应格式拼装

拆分示例

拆分示例
// 之前:OrderService 同时承担校验、定价、持久化三类变化
// 之后:按变化原因拆开
class OrderValidator { }     // 校验规则变化时只改这里
class Pricer { }             // 定价策略变化时只改这里
class OrderRepository { }    // 存储方式变化时只改这里

拆分依据

依据例子说明
变化原因校验、定价、持久化各自变化按原因拆,不按技术层次硬拆
变更频率某部分每周改、某部分每年改高频部分独立出来更稳
使用方不同角色关心不同部分便于按需替换与单独测试
拆分前先记录一段时间内这个类被修改的原因,按原因聚类。凭直觉拆出的模块常常只是把代码切碎,耦合仍然留在原处。
不要按技术层次硬拆(全都拆成工具类):缺乏领域含义的碎片更难复用,调用方要在多个类之间来回跳。

易错点

  • 按技术层次硬拆:拆出一堆无领域含义的工具类,复用性反而下降
  • 拆完职责仍然交叉:只换了文件位置,变化原因没有隔离
  • 过早拆分:还没看清变化方向就动手,之后又要合并回来
  • 只拆数据不拆行为:实体变成数据袋,行为留在原处继续膨胀

数据来源与参考

  • 《重构》第 2 版 · 第 3 章(Divergent Change)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌