• 重构手法之重新组织函数【3】



     返回总目录


    5 Introduce Explaining Variable(引用解释性变量)

    概要

    你有一个复杂的表达式。

    将该复杂表达式(或其中一部分)的结果放进一个临时变量,以此变量名称来解释表达式用途。

    动机

    有时候你会遇到一系列复杂的表达式连续运算的时候,这个时候你可能根本招架不住如此长或者是如此复杂的长函数。这个时候你可以通过引用临时变量来储存他们的结果,将这些长函数的结果分成一个个临时变量来让函数清晰化。这个重构手法在条件逻辑中用的比较多。

    我们来看这样一个条件判断:

    if(platform.ToUpper().IndexOf("MAC")>-1&&browser.ToUpper().IndexOf("IE")>-1&&  wasInitialized()&&resize>0)
    {
       //do something          
    }

    是不是看上去晕晕的,不知道这个条件判断是判断什么的?

    我们用这个手法重构一下:

     bool isMacOs = platform.ToUpper().IndexOf("MAC") > -1;
     bool isIEBrowser = browser.ToUpper().IndexOf("IE") > -1;
     bool wasResized = resize > 0;
     if (isMacOs && isIEBrowser && wasInitialized()&& wasResized)
     {
         //do something   
     }  

    这样代码是不是很清晰。

    范例

    我们从一个简单的计算开始:

    double GetPrice()
    {
        return _quantity * _itemPrice - Math.Max(0, _quantity - 500) * _itemPrice * 
        0.05 +  Math.Min(_quantity * _itemPrice * 0.1, 100.0);
    }     

    这段代码很简单,但是不好理解。可以进行Introduce Explaning Variable,将_quantity * _itemPrice的计算结果放进临时变量中。

    double GetPrice()
    {
        double basePrice = _quantity * _itemPrice;
        return basePrice - Math.Max(0, _quantity - 500) * _itemPrice * 0.05 +
               Math.Min(basePrice * 0.1, 100.0);
    }

    再将折扣提炼出来。

    double GetPrice()
    {
        double basePrice = _quantity * _itemPrice;
        double quantityDiscount = Math.Max(0, _quantity - 500) * _itemPrice * 0.05;
        return basePrice - quantityDiscount + Math.Min(basePrice * 0.1, 100.0);
    }

    最后把运费计算提炼出来。最终代码如下。

    double GetPrice()
    {
        double basePrice = _quantity * _itemPrice;
        double quantityDiscount = Math.Max(0, _quantity - 500) * _itemPrice * 0.05;
        double shipping = Math.Min(basePrice * 0.1, 100.0);
        return basePrice - quantityDiscount + shipping;
    }

    这里虽然完成了,但是我们前面讲过,临时变量只在它所处的那个函数中才有意义,局限性较大,函数则可以在对象的整个生命中都有用,并且可以被其他对象使用。所以下面我们使用Extract Method方法对刚刚的示例进行重构。同时我们也推荐使用这种方法。

    运用Extract Method处理上述范例

    同样这样一个函数:

    double GetPrice()
    {
        return _quantity * _itemPrice - Math.Max(0, _quantity - 500) * _itemPrice * 
        0.05 +  Math.Min(_quantity * _itemPrice * 0.1, 100.0);
    }     

    这一次我们把底价计算、批发折扣以及运费都提炼到一个新函数中。最终代码如下:

    double GetPrice()
    {
        return GetBasePrice() - GetQuantityDiscount() + GetShipping();
    }
    
    private double GetQuantityDiscount()
    {
        return Math.Max(0, _quantity - 500) * _itemPrice * 0.05;
    }
    
    private double GetBasePrice()
    {
         return _quantity * _itemPrice;
    }
    
    private double GetShipping()
    {
         return Math.Min(GetBasePrice() * 0.1, 100.0);
    }

    比较两种手法

    对比Extract Method和Introduce Explaining Variable这两种手法生成的函数:

    1、前者生成的函数更短,更清晰易懂,而后者则产生了大量的临时变量,使函数变得更长;

    2、前者生成了很多的独立函数,如果想在外部访问某个函数,直接调用就好,而后者得重新写方法供其调用。

    小结

    我个人比较推荐Extract Method这种手法,因为同一对象中的任何部分,都可以根据自己的需要取用这些提炼出来的函数。一开始我们可以把函数声明为private;如果其他对象需要它们,再释放这些函数的访问限制。

    既然如此,那么我们什么时候使用Introduce Explaining Variable呢?在Extract Method这种手法需要花费更大工作量时。比如说,有一个拥用大量局部变量的算法,这时候用Extract Method这个手法就不好处理。

    To Be Continued...

  • 相关阅读:
    Minimum Cost POJ
    SPFA费用流模板
    ISAP模板
    822D My pretty girl Noora
    822C Hacker, pack your bags!
    Dinic模板
    extjs最普通的grid
    springmvc配置首页的方式
    JSTL select和checkbox的用法
    请教<context:component-scan/>和<mvc:annotation-driven/>的区别20
  • 原文地址:https://www.cnblogs.com/liuyoung/p/7840954.html
Copyright © 2020-2023  润新知