所谓的以查询取代临时变量:就是当你的程序以一个临时变量保存某一个表达式的运算效果。将这个表达式提炼到一个独立函数中。将这个临时变量的所有引用点替换为对新函数的调用。此后,新函数就可以被其他函数调用。

例子如下:

double basePrice = _quantity*_itemPrice;

            if (basePrice > 1000)

            {

                return basePrice * 0.95;

            }

            else

            {

                return basePrice * 0.98;

            }

重构之后代码:

if (BasePrice() > 1000)

            {

                return BasePrice() * 0.95;

            }

            else

            {

                return BasePrice() * 0.98;

            }

………

private int BasePrice()

        {

            return _quantity* _itemPrice;

        }

引用书中原文来说:

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

Replace Temp with Query (以查询取代临时变量)往往是你运用Extract Method (提炼函数)之前必不可少的一个步骤。局部变量会使代码难以被提炼,所以你应该尽可能把它们替换为查询式。

这个重构手法较为简单的情况是:临时变量只被赋值一次,或者赋值给临时变量的表达式不受其他条件影响。其他情况比较棘手,但也可能发生。你可能需要先运用Split Temporary Variable (分解临时变量)或Separate Query form Modifier (将查询函数和修改函数分离)使情况变得简单一些,然后再替换临时变量。如果你想替换的临时变量是用来收集结果的)例如循环中的累加值),就需要将某些程序逻辑(例如循环)复制到查询函数去。

做法:1、找出只被赋值一次的临时变量。如果某个临时变量被赋值超过一次,考虑使用Split Temporary Variable (分解临时变量)将它们分解成多个变量。

2、将该变量声明为final。

3、编译。这可确保临时变量的确只被赋值一次。

4、将“对该临时变量赋值”之语句的等号右侧部分提炼到一个独立函数中。首先将函数声明为private。日后你可能会发现有更多的类需要使用它。那是放松对它的保护也很容易。确保提炼出来的函数无任何副作用,也就是说该函数并不修改任何对象内容。如果它有副作用,就对它进行Separate Query form Modifier (将查询函数和修改函数分离).

5、编译,测试。

6、在该变量身上实施 Inline Temp (内联临时变量)。

我们常常使用临时变量保存循环中的累加信息。在这种情况下,这个循环都可以被提炼为一个独立函数,这也使原本的函数可以少掉几行扰人的循环逻辑。有时候,你可能会在一个循环中累加好几个值。这种情况下你应该针对每个累加值重复一遍循环,这样就可以将所有临时变量都替换为查询。当然,循环应该很简单,复制这些代码才不会带来危险。

运用此手法,你可能会担心性能问题。和其他问题一样,我们现在不管它,因为它十有八九根本不会造成任何影响。若是性能真的出了问题,你也可以在优化时期解决它。代码组织良好,你往往能发现更有效的优化方案。如果没用进行重构,好的优化方案就可能与你失之交臂。如果性能实在太糟糕,要把临时变量放回去也很容易。

那么如何使用eclipse来快速重构呢?

Eclipse refactor菜单中没有直接的对应项,

不过仍可以简单的组合[ExtractMethod] + [Inline] 完成对应的重构

//  选中_quantity * _itemPrice,应用[Extract Method]

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, 应用[Inline] 

    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;

    }

总结:使用此种手段重构,一般仅限于在此函数内部存在局部变量,并且这个局部变量只赋值一次,其它地方都是引用;那么这个时候就可以采用使用查询来代替临时变量了;但是如果这个变量只是赋值一次,并且也就只使用了一次,那么简易直接采用临时变量内联的方式解决。

小技巧:如何看这个临时的局部变量是否只赋值一次,我们可以将其声明为final类,如果再出现赋值,那么就会报错了。

重构改善既有代码设计--重构手法04:Replace Temp with Query (以查询取代临时变量)的更多相关文章

  1. 重构改善既有代码设计--重构手法08:Replace Method with Method Object (以函数对象取代函数)

    你有一个大型函数,其中对局部变量的使用,使你无法釆用 Extract Method. 将这个函数放进一个单独对象中,如此一来局部变量就成了对象内的值域(field) 然后你可以在同一个对象中将这个大型 ...

  2. 重构改善既有代码设计--重构手法01:Extract Method (提炼函数)

    背景: 你有一段代码可以被组织在一起并独立出来.将这段代码放进一个独立函数,并让函数名称解释该函数的用途. void PrintOwing(double amount) { PrintBanner() ...

  3. 重构改善既有代码设计--重构手法02:Inline Method (内联函数)& 03: Inline Temp(内联临时变量)

    Inline Method (内联函数) 一个函数调用的本体与名称同样清楚易懂.在函数调用点插入函数体,然后移除该函数. int GetRating() { return MoreThanfiveLa ...

  4. 重构改善既有代码设计--重构手法06:Split Temporary Variable (分解临时变量)

    你的程序有某个临时变量被赋值超过一次,它既不是循环变量,也不被用于收集计算结果.针对每次赋值,创造一个独立.对应的临时变量 double temp = 2 * (_height + _width); ...

  5. 重构改善既有代码设计--重构手法07:Remove Assignments to Parameters (移除对参数的赋值)

    代码对一个 参数赋值.以一个临时变量取代该参数的位置.     int Discount(int inputVal, int quantity, int yearTodate) { if (input ...

  6. 重构改善既有代码设计--重构手法05:Introduce Explaining Variable (引入解释性变量)

      发现:你有一个复杂的表达式. 解决:将该复杂的表达式(或其中的部分)的结果放进一个临时变量,并以此变量名称来解释表达式用途. //重构前 if((platform.toUpperCase().in ...

  7. 重构改善既有代码设计--重构手法16:Introduce Foreign Method (引入外加函数)&& 重构手法17:Introduce Local Extension (引入本地扩展)

    重构手法16:Introduce Foreign Method (引入外加函数)你需要为提供服务的类增加一个函数,但你无法修改这个类.在客户类中建立一个函数,并以第一参数形式传入一个服务类实例. 动机 ...

  8. 重构改善既有代码设计--重构手法11:Move Field (搬移字段)

    你的程序中,某个字段被其所驻类之外的另一个类更多的用到.在目标类建立一个新字段,修改源字段的所有用户,令它们改用新字段.        动机:在类之间移动状态和行为,是重构过程中必不可少的措施.随着系 ...

  9. 重构改善既有代码设计--重构手法19:Replace Data Value with Object (以对象取代数据值)

    你有一笔数据项(data item),需要额外的数据和行为. 将这笔数据项变成一个对象. class Order... private string customer; ==> class Or ...

随机推荐

  1. LNMP环境+ 前后端项目部署+redis+redis扩展

    LNMP 环境    (参照https://lnmp.org/install.html) wget -c http://soft.vpser.net/lnmp/lnmp1.4.tar.gz & ...

  2. HashMap和HashTable源码分析

    HashMap HashMap是一个实现了Map接口的Hash表.提供所有Map的操作,并且允许null key和null value.HashMap几乎等同于HashTable,只不过HashMap ...

  3. IT就业·软件工程之我见

    随着计算机技术的飞速发展,让人们深切感受到科技让生活更美好的真正含义. 现如今我们的正常生活,社交都越来越离不开网络和终端,因特网和各种终端设备的组合让我们即使相距千里,也能面对面对话交流:购物,我们 ...

  4. node.js入门(一)

    NodeJS是一个使用了Google高性能V8引擎的服务器端JavaScript实现.它提供了一个(几乎)完全非阻塞I/O栈,与JavaScript提供的闭包和匿名函数相结合,使之成为编写高吞吐 量网 ...

  5. 使用vue-cli3新建一个项目,并写好基本配置

    1. 使用vue-cli3新建项目: https://cli.vuejs.org/zh/guide/creating-a-project.html 注意,我这里用gitbash不好选择选项,我就用了基 ...

  6. sql 两列数据交换

    MSSQL的处理方法   update table1 set field_1 = field_2, field_2 = field_1 可是MySQL就不能这样写,不然一列会覆盖另一列记录   MyS ...

  7. pyspark在windows中的安装

    0.安装python,我用的是python2.7.13 1.安装jdk 一定要安装1.7以上的版本,安装低版本会报下面的错误 java.lang.NoclassDefFoundError 安装后不用手 ...

  8. 第163天:js面向对象-对象创建方式总结

    面向对象-对象创建方式总结 1. 创建对象的方式,json方式 推荐使用的场合: 作为函数的参数,临时只用一次的场景.比如设置函数原型对象. var obj = {}; //对象有自己的 属性 和 行 ...

  9. iOS 通过网络请求获取图片的下载歌曲

    1.导入代理<NSURLConnectionDataDelegate> @interface ViewController ()<NSURLConnectionDataDelegat ...

  10. 最小生成树-Borůvka算法

    一般求最小生成树的时候,最流行的是Kruskal算法,一种基于拟阵证明的贪心,通过给边排序再扫描一次边集,利用并查集优化得到,复杂度为\(O(ElogE)\).另一种用得比较少的是Prim算法,利用优 ...