NaYoung 阅读(164) 评论(0)

 返回总目录


6.4Replace Temp with Query(以查询取代临时变量)

概要

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

将这个表达式提炼到一个独立函数中。将这个临时变量的所有引用点替换为对函数的调用。此后,新函数就可以被其他函数使用。

动机

临时变量的问题在于:只在当前函数可见。如果你在同类的别的地方访问这个变量,你就必须重新写表达式来获取这个变量,这样的话你就会在不经意间让你的函数变得复杂起来。如果将临时变量替换为一个查询,那么同类中所有函数都可以获得这份信息。

所以如果你想要使用Extract Method,那么Replace Temp with Query是必不可少的一个步骤。而我们前面介绍的Inline Temp其实是这个手法的一部分,两者的区别在于Inline Temp已经有了表达式自身,只需要做简单的替换就可以,需要用表达式本身把临时变量给去掉。而Replace Temp with Query更加全面,里面包含了提炼表达式到函数本身,然后替换引用点(Inline Temp)。如果你把所有的临时变量都替换为一个查询,你的类的结构和逻辑将非常清晰,这样将更加有利于你的重构和进行优化。

范例

假设有以下简单函数:

double GetPrice()
{
   int basePrice = _quantity * _itemPrice;
   double discountFactor;
   if (basePrice > 1000)
   {
       discountFactor = 0.95;
   }
   else
   {
       discountFactor = 0.98;
   }
   return basePrice * discountFactor;
}    

我们现在将basePrice 和discountFactor这两个临时变量都替换掉。

先来替换basePrice,将basePrice右侧表达式提炼出来,然后使用Inline Temp将basePrice的所有引用点都替换掉,并且把basePrice临时变量的声明去掉。

现在代码变成这样:

double GetPrice()
{
   double discountFactor;
   if (GetBasePrice() > 1000)
   {
      discountFactor = 0.95;
   }
   else
   {
      discountFactor = 0.98;
   }
   return GetBasePrice() * discountFactor;
 }

private int GetBasePrice()
{
   return _quantity * _itemPrice;
}

再以类似的方法提炼出GetDiscountFactor();

private double GetDiscountFactor()
{
   if (GetBasePrice() > 1000)
   {
       return 0.95;
   }
   return 0.98;
}

最终代码是这样的。

double GetPrice()
{
   return GetBasePrice() * GetDiscountFactor();
}

private double GetDiscountFactor()
{
    if (GetBasePrice() > 1000)
    {
        return 0.95;
    }
   return 0.98;
}

private int GetBasePrice()
{
   return _quantity * _itemPrice;
}

可以明显的看到,这个重构手法对于函数本身来说,提高了清晰度,也让我们进行后期重构能够更加便捷。

小结

我们常常在循环中用临时变量保存累加信息。如果是这种情况的话,我们可以将整个循环都提炼出来。如果在循环中要累加好几个值,那么就应该针对每个累加值重复一遍循环。这样,就可以很方便的将所有临时变量都替换为查询。

当然,这样一来,我们可能担心性能问题。本来我定义一个临时变量只需要查询一次,现在我每次都要去做查询。这个我们完全不必担心。重构的目的是让程序更加清晰,有了更加清晰的程序之后再具体做优化也不迟,况且根据二八原则,仅仅这条查询语句倘若你系统真的出现了性能问题也不大可能,如果实在是因为这条语句,你也可以把变量再放回去。

 

To Be Continued...