首页 > 代码库 > 重构笔记——分解临时变量

重构笔记——分解临时变量

本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/42463871


        在上一篇文章中介绍了“重构笔记——引入解释性变量“。本文将介绍“分解临时变量”这种重构手法。

        下面让我们来学习这种重构手法吧。 


开门见山

        发现:你的程序有某个临时变量被赋值超过一次,它既不是循环变量,也不被用于收集计算结果。

        解决:针对每次赋值,创造一个独立、对应的临时变量。

	//重构前
	double temp = 2 * (_height + _width);
	System.out.println(temp);
	temp = _height + _width;
	System.out.println(temp);
	//重构后
	final double perimeter = 2 * (_height + _width);
	System.out.println(perimeter);
	final double area = _height + _width;
	System.out.println(area);



动机

        在某些情况下,临时变量用于保存一段冗长代码的运算结果,以便稍后使用。这种临时变量应该只被赋值一次。如果它被赋值超过一次,就意味着它们在函数中承担了一个以上的责任。如果临时变量承担多个责任,它就应该被替换(分解)为多个临时变量,使得每一个变量只承担一个责任。同一个临时变量承担两件不同的事情,会让代码阅读者糊涂。



做法

(1)在待分解临时变量的声明及第一次被赋值处,修改其名称。
(2)将新的临时变量声明为final。
(3)以该临时变量的第二次赋值动作为界,修改此前对该临时变量的所有引用点,让它们引用新的临时变量。
(4)在第二次赋值处,重新声明原先那个临时变量。
(5)编译,测试。
(6)逐次重复上述过程。每次都在声明处对临时变量改名,并修改下次赋值之前的引用点。


示例

        我们从一个简单计算开始:我们需要计算一个苏格兰布丁运动的距离。在起点处,静止的布丁会受到一个初始力的作用而开始运动。一段时间后,第二个力作用于布丁,让它再次加速。根据牛顿第二定律,计算布丁运动距离:
double getDistance(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;
}
        代码看起来好像有点丑陋。观察例子中的acc变量是如何被赋值两次。
        acc变量有两个责任,一是保存第一个力产生的加速度;二是保存两个力共同产生的加速度。这就是需要分解的东西。

        首先,在函数开始修改处修改这个临时变量的名称,并将新的临时变量声明为final。然后,把第二次赋值之前对acc变量的所有引用点,全部改用心的临时变量。最后,在第二次赋值处重新声明acc变量。
double getDistance(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;
}
        新的临时变量指出,它只承担原先acc变量的第一个责任。将它声明为final,确保它只被赋值一次。然后,在原先acc变量第二次被赋值处重新声明acc。现在,重新编译并测试,一切都没有问题。
        然后继续处理acc临时变量的第二次赋值。
double getDistance(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;
		final double secondaryAcc = (_primaryForce + _secondaryForce) / _mass;
		result += primaryVel * secondaryTime + 0.5 * secondaryAcc * secondaryTime * secondaryTime;
	}
	return result;
}
        现在,我想你一定会想到前几篇文章中的一些重构手法,那就尽情使用吧。
//“以查询取代临时变量”手法进行重构
double getDistance(int time){
	double result= 0.5 * getPrimaryAcc() * getPrimaryTime(time) * getPrimaryTime(time);
	if(getSecondaryTime(time) > 0){
		result += getSeconddistance();
	}
	return result;
}

private double getPrimaryAcc(){
	return _primaryForce / _mass;
}

private double getSecondaryAcc(){
	return (_primaryForce + _secondaryForce) / _mass;
}

private int getPrimaryTime(int time){
	return Math.min(time, _delay);
}

private int getSecondaryTime(int time){
	return time - _delay;
}

private double getSeconddistance(){
	return getPrimaryAcc() *_delay * getSecondaryTime(time) 
			+ 0.5 * getSecondaryAcc() * getSecondaryTime(time) * getSecondaryTime(time);
}

        本文主要介绍了重构手法——分解临时变量。该重构手法主要针对于变量被赋值多次的情况。一旦函数中的临时变量比较多,且被赋值多次,就比较容易出现问题,阅读代码也很吃力,有必要对其进行调整,让其变得整洁。另外,通过上述示例可以发现,当你在使用一种重构手法的过程中,总是不觉间联想到其它的重构手法,无形中就指引你把代码整理的更好。
        最后,希望本文对你有所帮助。有问题可以留言,谢谢。(PS:下一篇将介绍重构笔记——移除对参数的赋值)


重构笔记文章如下

       重构笔记——入门篇

       重构笔记——代码的坏味道(上)

       重构笔记——代码的坏味道(下)

       重构笔记——构筑测试体

       重构笔记——提炼函数

       重构笔记——内联函数

       重构笔记——内联临时变量

       重构笔记——以查询取代临时变量

       重构笔记——引入解释性变量



重构笔记——分解临时变量