首页 > 代码库 > 以查询取代临时变量

以查询取代临时变量

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


        在上一篇文章中介绍了“ 内联临时变量“。本文将介绍“以查询取代临时变量”这种重构手法。

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


开门见山

        发现:你的程序以一个临时变量保存某一表达式的运算结果。

        解决:将这个表达式提炼到一个独立函数中。将这个临时变量的所有引用点替换为对新函数的调用。

	//重构前
	double basePrice = _quantity * _itemPrice;
	if(basePrice > 5000)
		return basePrice * 0.95;
	else
		return basePrice * 0.98;
	//重构后
	if(basePrice() > 5000)
		return basePrice() * 0.95;
	else
		return basePrice() * 0.98;
	...
	
	double basePrice(){
		 return  _quantity * _itemPrice;
	}


动机

        我们都知道临时变量都是暂时的,而且只能在所属的函数中使用。所以它们会驱使你写出更长的函数,因为只有这样你才能访问到需要的临时变量。如果把临时变量替换为一个查询,那么同一个类中所有函数都将可以获得这份信息。这将带给你极大帮助,使你能够为这个类编写出更清晰的代码。

        该重构方法往往是你运用提炼函数之前必不可少的一个步骤。局部变量会使得代码难以提炼,所以应该尽可能把它们替换为查询式。比较简单的情况是:临时变量只被赋值一次,或者赋值给临时变量的表达式不受其它条件影响。


做法

        对于简单的情况:
(1)找出只被赋值依次的临时变量(如果被使用多次,考虑将其分割成多个变量,对应在后续重构方法中)。
(2)将该临时变量声明为final。
(3)编译(确保该临时变量的确只被赋值一次)
(4)将“对该临时变量赋值”之语句的等号右侧部分提炼到一个独立的函数中。(首先将函数声明为private。日后你可能会发现还有好多地方需要使用它,那时放松对它的保护也很容易;确保提炼出的函数无任何副作用,即该函数不修改任何对象内容)
(5)编译,测试。
(6)对该临时变量实施“内联临时变量”重构方法。

        我们常常使用临时变量保存循环中的累加信息。在这种情况下,整个循环都可以被提炼为一个独立的函数,这可以减少原函数中几行循环逻辑代码。该手法的使用可能会让你担心性能上的问题。就像和其它性能问题一样,我们现在不用管它,因为十有八九根本没有造成任何影响。就算真的出问题了,你也可以在优化时期解决它。代码组织良好,你也会发现更有效的优化方案;如果没有进行重构,好的优化方案就可能与你失之交臂。


示例

        我们从一个简单函数开始:
//重构前
double getPrice() {
	int basePrice = _quantity * _itemPrice;
	double discountFactor;
	if (basePrice > 5000)
		discountFactor = 0.95;
	else
		discountFactor = 0.98;
	return basePrice * discountFactor;
}
        我们希望将其中的两个临时变量都去掉。当然,每次一个进行处理。
        代码虽然简单,但是还是有必要先把临时变量声明为final,检查它们是否的确只被赋值一次。
double getPrice() {
	final int basePrice = _quantity * _itemPrice;
	final double discountFactor;
	if (basePrice > 5000)
		discountFactor = 0.95;
	else
		discountFactor = 0.98;
	return basePrice * discountFactor;
}
        这样,一旦有问题编译器就会警告。之所以需要这个做是因为如果临时不安路口不只被赋值一次,就不该进行这项重构。
        下面开始替换临时变量,每次一个,不要着急,按部就班。
        首先,把赋值动作右侧表达式提炼出来:
double getPrice() {
	final int basePrice = basePrice();
	final double discountFactor;
	if (basePrice > 5000)
		discountFactor = 0.95;
	else
		discountFactor = 0.98;
	return basePrice * discountFactor;
}

private double basePrice() {
	return _quantity * _itemPrice;
}
        然后,编译并测试,再开始使用内联临时变量。
        首先把临时变量basePrice的第一个引用点替换掉:
double getPrice() {
	final int basePrice = basePrice();
	final double discountFactor;
	if (basePrice() > 5000)
		discountFactor = 0.95;
	else
		discountFactor = 0.98;
	return basePrice * discountFactor;
}
        编译、测试,然后进行下一个。由于下一个是最后一个引用点,所以把basePrice临时变量的声明式一并去掉:
double getPrice() {
	final double discountFactor;
	if (basePrice() > 5000)
		discountFactor = 0.95;
	else
		discountFactor = 0.98;
	return basePrice()  * discountFactor;
}
        完成basePrice之后,以类似的方法提炼出discountFactor():
double getPrice() {
	final double discountFactor = discountFactor() ;
	return basePrice()  * discountFactor;
}

private double discountFactor(){
	if (basePrice() > 5000)
		return 0.95;
	else
		return 0.98;
}
        你会发现,如果没有把临时变量basePrice替换为一个查询式,将多么难以提炼discountFactor()!
        最终,getPrice()变成这样:
//重构后
double getPrice() {
	return basePrice()  * discountFactor();
}

        本文主要介绍了重构手法——以查询取代临时变量。通过重构后代码可见,代码变的相当地简洁了,代码所表达的意图也变的很清晰了。一旦代码中出现问题,修改起来也比较轻松,因为代码很简短、清晰。我想你是否也慢慢喜欢上重构了呢!如果是,那么就一起学习、进步,让代码变得漂亮吧!
        最后,希望本文对你有所帮助。有问题可以留言,谢谢。(PS:下一篇将介绍重构笔记——引入解释性变量)


重构笔记文章如下

       重构笔记——入门篇

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

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

       重构笔记——构筑测试体

       重构笔记——提炼函数

       重构笔记——内联函数

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


以查询取代临时变量