如果某个临时变量被赋值超过一次,并且它既不是循环变量,也不是集用临时变量。
。「循环变量」和「集用临时变量」就是两个典型例子:
循环变量(loop variables )[Beck]会随循环的每次运行而改变〔例如for (int i=0; i<10; i++)语句中的i〕;
集用临时变量(collecting temporary variable)[Beck]负责将「通过整个函数的运算」而构成的某个值收集起来。
除了这两种情况,还有很多临时变量用于保存一段冗长代码的运算结果,以便稍后使用。这种临时变量应该只被赋值一次。如果它们被赋值超过一次,就意味它们在函数中承担了一个以上的责任。如果临时变量承担多个责任,它就应该被替换(剖 解)为多个临时变量,每个变量只承担一个责任。
最好一个临时变量只是承担一个责任。
作法(Mechanics)
· | 在「待剖解」之临时变量的声明式及其第一次被赋值处,修改其名称。 |
Ø | 如果稍后之赋值语句是「i = i +某表达式」形式,就意味这是个集用临时变量,那么就不要剖解它。集用临时变量的作用通常是累加、字符串接合、写入stream或者向群集(collection)添加元素。 |
· | 将新的临时变量声明为final。 |
· | 以该临时变量之第二次赋值动作为界,修改此前对该临时变量的所有引用点,让它们引用新的临时变量。 |
· | 在第二次赋值处,重新声明原先那个临时变量。 |
· | 编译,测试。 |
· | 逐次重复上述过程。每次都在声明处对临时变量易名,并修改下次赋值之前的引用点。 |
例子:
下面范例中我要计算一个苏格兰布丁(haggis)运动的距离。在起点处,静止的苏格兰布丁会受到一个初始力的作用而开始运动。一段时间后,第二个力作用于布丁,让它再次加速。根据牛顿第二定律,我可以这样计算布丁运动的距离:
double getDistanceTravelled (int time) {
double result;
double acc = _primaryForce / _mass; //译注:第一次赋值处
int primaryTime = Math.min(time, _delay);
result = 0.5 * acc * primaryTime * primaryTime;
int secondaryTime = time - _delay;
if (secondaryTime > 0) {
double primaryVel = acc * _delay; //以下是第二次赋值处
acc = (_primaryForce + _secondaryForce) / _mass;
result += primaryVel * secondaryTime + 0.5 * acc * secondaryTime * secondaryTime;
}
return result;
}
步骤:1:在函数开始处修改这个临时变量的名称,并将新的临时变量声明为final。接下来把第二次赋值前对acc变量所有的引用变为新的临时变量;最后在第二次赋值处重新声明acc变量。
double getDistanceTravelled (int time) {
double result;
final double primaryAcc = _primaryForce / _mass;
int primaryTime = Math.min(time, _delay);
result = 0.5 * primaryAcc * primaryTime * primaryTime;
int secondaryTime = time - _delay;
if (secondaryTime > 0) {
double primaryVel = primaryAcc * _delay;
double acc = (_primaryForce + _secondaryForce) / _mass;
result += primaryVel * secondaryTime + 0.5 * acc * secondaryTime * secondaryTime;
}
return result;
}
这种情况应该不会常见,如果重构的时候遇到这个问题就要这么处理。比较简单,总的来说就是一个原则:
一个临时变量只是承担一个责任。