首页/开发/代码质量与评审速查/手法:Split Variable(拆分变量)
重构手法62 条

手法:Split Variable(拆分变量)

同一变量被赋予不同含义的值时,拆成多个各自命名的变量:变量名准确、范围缩小,副作用减少;循环变量与收集变量常是重灾区。

Split Variable 是什么

同一个变量被赋予含义不同的值时,拆成多个各自命名的变量:变量名准确、作用范围缩小、副作用减少。被反复重赋值的临时变量是重灾区——它先表示「临时结果」,后又表示「最终结果」,读者必须逐行追踪才能知道当前这个值代表什么。拆开之后,每个变量只承担一个含义。

基本信息

信号变量被重新赋值且含义改变,需要写注释说明
做法每个含义一个变量,能声明为不可变就声明
配套循环中的累计变量可拆分或提炼为函数
收益缩小可变范围,减少因误用导致的缺陷

常见形态

  • 一个 result 变量先后存放中间结果与最终结果
  • 循环里用同一个变量既当索引又当累计值
  • 输入参数被就地改写后再当作输出使用
  • 布尔变量在函数中途被改含义(先表示「已找到」,后表示「失败」)
  • 同一个变量在不同分支里承担不同语义,靠上下文区分

拆分示例

拆分示例
// 之前:temp 先放周长,再放面积
void report(double height, double width) {
    double temp = 2 * (height + width);
    System.out.println("perimeter: " + temp);
    temp = height * width;                 // 含义完全变了
    System.out.println("area: " + temp);
}

// 之后:一个含义一个名字,而且都不可变
void report(double height, double width) {
    final double perimeter = 2 * (height + width);
    final double area = height * width;
    System.out.println("perimeter: " + perimeter);
    System.out.println("area: " + area);
}

变量角色与拆分方式

角色常见问题处理
临时结果一词多义,含义漂移按含义拆名,改成不可变
累计值与索引混淆单独命名,或提炼为函数
收集器重置时机不清在循环内声明,避免跨轮复用
输出参数被就地改写改为返回值,调用方接收
能声明为不可变(final、const)就声明:编译期就挡住二次赋值,比靠评审提醒有效得多。做不到不可变时,至少让每个变量只在一个地方被赋值。
循环里的收集变量最容易拆错:如果把它提到循环外,多轮之间会相互污染;如果在循环内声明,每轮都是新实例,语义更清楚但要注意别在循环外引用。

易错点

  • 拆分后仍频繁重赋值:可变性并未真正收敛,问题只是被拆成两份
  • 循环收集变量拆错位置:重置时机不同导致结果变化,且难以察觉
  • 拆出的变量名依旧模糊(temp1、temp2):可读性没有实质提升
  • 只拆变量不收敛作用域:变量仍在很远处被引用,读者仍要跨屏追踪

数据来源与参考

  • 《重构》第 2 版 · 第 9 章(Split Variable)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌