refactoring笔记——代码重构的方法:Replace Temp with Query

这个重构技巧指,如果你有一个临时变量用来保存一个表达式的运算结果,那么就将这个表达式提炼到一个独立函数中,再将这个临时变量的所有引用点改为对新函数的调用。
    
    同样是一个消除临时变量的一个重构方法。我认为是Inline Temp的一个高级应用。因为Inline Temp只是把临时变量内联化了,但是如果临时变量所保存的是一个复杂的计算式,那么利用Extract Method方法后,就是本重构方法的思想了。

例1:
        
double basePrice = _quantity * _itemPrice;
        if (basePrice > 1000)
            return basePrice * 0.95;
        else
            return basePrice * 0.98;
    
    这段代码已经很简洁了,它使用一个临时变量“basePrice”保存了一个计算式的结果,并在后续代码中使用。重构后的代码如下:
    
        
if (basePrice() > 1000)
            return basePrice() * 0.95;
        else
            return basePrice() * 0.98;
    
    ...
    double basePrice() {
        return _quantity * _itemPrice;
    }
    
    这样重构后,临时变量就取消了,但是同时多出一个函数,那么其好处是:函数是可重用的,其它函数中均可再调用,而临时变量是只针对某个函数内部。以后只要单独维护basePrice函数就可以影响所有的调用者。调用的地方,代码的可读性也变得相当好。
    
    但是这种重构,也一定能看出是以代码性能作为代价的。没错,basePrice的计算式总是要被调用两次。我的看法是,任何事情都是鱼和熊掌不可兼得。代码是让机器跑的,高性能的代码必然直接干脆从而晦涩难读;代码是让人阅读让人写的,所以良好的设计、清晰的结构,也必然会降低性能。所以我们可以在项目的定位上来决定,把我们的代码对机器的高效运行与对人的高效阅读做一个合理的调节。不过如果你还不能很好的确定的话,那么一个建议是:先重构,再做优化。因为重构是理清代码思路,也是优化的前提,代码思路都不清楚,优化又从何谈起呢?所有重构时,就专注于重构,先不管优化的问题,如果对性能真有影响,那么可以在优化时期解决。
    
    再来看一个很经典的例子:

例2:
    
double getPrice() {
        int basePrice = _quantity * _itemPrice;
        double discountFactor;
        if (basePrice > 1000)
            discountFactor = 0.95;
        else
            discountFactor = 0.98;
        return basePrice * discountFactor;
    }
    
    这段代码有两个临时变量,分别用来保存两种表达式的结果,我们分步来重构:
    
    重构1:
        
double getPrice() {
            double discountFactor;
            if (basePrice() > 1000)
                discountFactor = 0.95;
            else
                discountFactor = 0.98;
          return basePrice() * discountFactor;
        }
      
        private int basePrice() {
            return _quantity * _itemPrice;
        }
  
   重构2:
      
double getPrice() {
          return basePrice() * discountFactor();
      }
      
      private int basePrice() {
          return _quantity * _itemPrice;
      }
      
      private double discountFactor() {
          if (basePrice() > 1000)
              return = 0.95;
          else
              return = 0.98;
      }
    
    重构后的代码逻辑非法清楚,各自函数也都干了各自最本分的事情。



官方解释:


Replace Temp with Query

You are using a temporary variable to hold the result of an expression.

Extract the expression into a method. Replace all references to the temp with the expression. The new method can then be used in other methods.

		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;
...
	double basePrice() {
		return _quantity * _itemPrice;
	}

For more information see page 120 of Refactoring

Additional Comments

Side Effects

Paul Haahr pointed out that you can't do this refactoring if the code in between the the assignment to the temp and the use of the temp changes the value of the expression that calculates the temp. In these cases the code is using the temp to snapshot the value of the temp when it's assigned. The name of the temp should convey this fact (and you should change the name if it doesn't).

He also pointed out that it is easy to forget that creating a reference object is a side effect, while creating a value object isn't.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值