重构--Replace Temp with Query(以查询取代临时变量)(六)
-
重构方式
-
你的程序以一个临时变量保存某一表达式的运算结果;将这个表达式提炼到一个独立函数中,将这个临时变量的所有引用点替换为对新函数的调用。此后,新函数就可被其他函数使用;
-
-
-
动机
-
临时变量的问题:
- 只能存在于所属函数;
- 会驱使函数变长,只有这样才能访问到需要的临时变量;
- Replace Temp with Query往往是在运用Extract Method之前必不可少的一个步骤;局部变量会使代码难以被提炼,所以应该尽可能把它们替换为查询式;
- 情况:临时变量只被赋值一次,或者赋值给临时变量的表达式不受其他条件影响;
-
-
做法
-
找出只被赋值一次的临时变量;
- 如果某个临时变量被赋值超过一次,考虑使用"分解临时变量"将它分割成多个变量;
- 将该临时变量声明为final;
-
编译
- 这可确保该临时变量的确只被赋值一次;
-
将"对该临时变量赋值"之语句的等号右侧部分提炼到一个独立函数中;
- 首先将函数声明为private。日后你可能会发现有更多类需要使用它,那时放松对它的保护也很容易;
- 确保提炼出来的函数无任何副作用,也就是说该函数并不修改任何对象内容。
- 编译,测试。
- 对该临时变量使用"内联临时变量";
-
特别说明:
- 我们常使用临时变量保存循环中的累加信息。在这种情况下,整个循环都可以被提炼为一个独立函数,这也使原本的函数可以少掉几行循环逻辑。
- 有时,你可能会在一个循环中累加好几个值。这种情况下应该针对每个累加值重复一遍循环,这样就可以将所有临时变量都替换为查询;
-
-
范例
- 示例代码:将这两个临时变量都替换掉,每次一个;
double getPrice(){ int basePrice = _quantity * _itemPrice; double discountFactor; if(basePrice > 1000){ discountFactor = 0.95; } else { discountFactor = 0.98; } return basePrice * discountFactor; } |
- 保险起见,先把临时变量声明为final,检查它们是否的确只被赋值一次,如果临时变量并没有被赋值一次,就不应该进行这次重构:
double getPrice(){ final int basePrice = _quantity * _itemPrice; final double discountFactor; if(basePrice > 1000){ discountFactor = 0.95; } else { discountFactor = 0.98; } return basePrice * discountFactor; } |
- 开始替换临时变量,先把赋值动作的右侧表达式提炼出来:
double getPrice(){ final int basePrice = basePrice(); final double discountFactor; if(basePrice > 1000){ discountFactor = 0.95; } else { discountFactor = 0.98; } return basePrice * discountFactor; }
private int basePrice(){ return _quantity * _itemPrice; } |
- 把临时变量basePrice的引用点替换掉:
double getPrice(){ final double discountFactor; if(basePrice() > 1000){ discountFactor = 0.95; } else { discountFactor = 0.98; } return basePrice() * discountFactor; }
private int basePrice(){ return _quantity * _itemPrice; } |
- 提炼discountFactor():
double getPrice(){ return basePrice() * discountFactor(); }
private double discountFactor() { if(basePrice() > 1000){ return 0.95; } else { return 0.98; } }
private int basePrice(){ return _quantity * _itemPrice; } |