zoukankan      html  css  js  c++  java
  • 重构手法之简化条件表达式【1】

    返回总目录

    本小节目录

    1Decompose Conditional(分解条件表达式)

    概要

    你有一个复杂的条件(if-else if-else)语句。

    从if、else if、else三个段落中分别提炼出独立函数。

    动机

    复杂的条件逻辑往往会导致程序复杂度上升。编写代码来检查不同的条件分支、根据不同的分支做不同的事往往又会导致函数过长。

    将条件表达式分解为多个独立函数,根据每个小块代码的用途,为分解而得的新函数命名,并将原函数中对应的代码改为调用新建函数,从而更清楚地表达自己的意图。对于条件逻辑,将每个分支条件分解成新函数还可以突出条件逻辑,更清楚地表明每个分支的作用,并且突出每个分支的原因。

    范例

    假设要计算购买某样商品的总价,而这个商品在冬天和夏天的单价是不同的:

    class Order
    {
        public double Quantity { get; set; }
    
        public double WinterRate { get; set; }
    
        public double SummerRate { get; set; }
    
        public double WinterServiceCharge { get; set; }
    
        public double GetCharge(DateTime date)
        {
            double result;
            if (date.Month < 3 || date.Month > 6)
            {
                result = Quantity * WinterRate + WinterServiceCharge;
            }
            else
            {
                result = Quantity * SummerRate;
            }
            return result;
        }
    
    }

    现在把每个分支的判断条件都提炼到一个独立函数中:

    class Order
    {
        public double Quantity { get; set; }
    
        public double WinterRate { get; set; }
    
        public double SummerRate { get; set; }
    
        public double WinterServiceCharge { get; set; }
    
    
        public double GetCharge(DateTime date)
        {
            double result;
            if (NotSummer(date))
            {
                result = WinterCharge(Quantity);
            }
            else
            {
                result = SummerCharge(Quantity);
            }
            return result;
        }
    
        private bool NotSummer(DateTime date)
        {
            return date.Month < 3 || date.Month > 6;
        }
        private double SummerCharge(double quantity)
        {
            return quantity * SummerRate;
        }
    
        private double WinterCharge(double quantity)
        {
            return quantity * WinterRate + WinterServiceCharge;
        }
    }

    通过这段代码可看出整个重构带来的清晰性。

    小结

    像上面这样的情况,很多人都不会去提炼分支条件。因为这些分支条件往往非常短,看上去似乎没有提炼的必要。但是,尽管这些条件往往很短,在代码意图和代码自身之间往往存在不小的差距。就像上面那样,NotSummer(date)这个语句比原本的代码更好地表达自己的意图。原来的代码,我必须看看,想一想,才能说出其作用。当然了,这里看起来似乎很简单。即使是这样,提炼出来的函数可读性也更高一些。

    2Consolidate Conditional Expression(合并条件表达式)

    概要

    你有一系列条件测试,都得到相同结果。

    将这些测试合并为一个条件表达式,并将这个条件表达式提炼成为一个独立函数。

    动机

    代码里经常有这样的检查:检查条件各不相同,最终行为却一致。如果发现这种情况,应该使用“逻辑与”和“逻辑或”将它们合并为一个条件表达式。

    之所以合并条件代码,有两个原因。(1)合并后的条件代码会告诉你“实际上只有一次条件检查,只不过有多个并列条件需要检查而已”,从而使这一次检查的用意更清晰。(2)这项重构往往是为了使用Extract Method做好准备。

    范例:使用逻辑或

    class Amount
    {
        public int Seniority { get; set; }
    
        public int MonthsDisabled { get; set; }
    
        public bool IsPartTime { get; set; }
    
        double DisablilityAmount()
        {
            if (Seniority < 2)
            {
                return 0;
            }
            if (MonthsDisabled > 12)
            {
                return 0;
            }
            if (IsPartTime)
            {
                return 0;
            }
            //compute the disability amount
            //your code here
            return 1;
        }
    }

    这段代码中,一连串的条件检查都在做同一件事情。对于这样的代码,上述检查等价于一个以逻辑或连接起来的语句:

    class Amount
    {
        public int Seniority { get; set; }
    
        public int MonthsDisabled { get; set; }
    
        public bool IsPartTime { get; set; }
    
        double DisablilityAmount()
        {
            if (Seniority < 2 || MonthsDisabled > 12 || IsPartTime)
            {
                return 0;
            }
            //compute the disability amount
            //your code here
            return 1;
        }
    }

    现在,我们观察这个新的条件表达式,并运用Extract Method将它提炼成一个独立函数,以函数名称表达该语句所检查的条件:

    class Amount
    {
        public int Seniority { get; set; }
    
        public int MonthsDisabled { get; set; }
    
        public bool IsPartTime { get; set; }
    
        double DisablilityAmount()
        {
            if (IsNotEligibleForDisability())
            {
                return 0;
            }
            //compute the disability amount
            //your code here
            return 1;
        }
    
        bool IsNotEligibleForDisability()
        {
            return Seniority < 2 || MonthsDisabled > 12 || IsPartTime;
        }
    }

    范例:使用逻辑与

    class Rate
    {
        public double GetRate()
        {
            if (OnVacation())
            {
                if (LengthOfService() > 10)
                {
                    return 1;
                }
            }
            return 0.5;
        }
        private bool OnVacation()
        {
            return true;
        }
        private int LengthOfService()
        {
            return 9;
        }
    }

    这段代码可以变成这样:

    class Rate
    {
        public double GetRate()
        {
            if (OnVacation() && LengthOfService() > 10)
            {
                return 1;
            }
            return 0.5;
        }
        private bool OnVacation()
        {
            return true;
        }
        private int LengthOfService()
        {
            return 9;
        }
    }

    如果所观察的部分只是对条件进行检查并返回一个值,就可以使用三元操作符将这一部分变成一条return语句。因此,下列代码:

    if (OnVacation() && LengthOfService() > 10)
    {
        return 1;
    }
    return 0.5;

    就变成了:

    return (OnVacation() && LengthOfService() > 1) ? 1 : 0.5;

    小结

    那我们什么时候不需要合并表达式呢?

    即我们认为这些检查的确彼此独立,的确不应该被视为同一次检查,那就不使用本项重构。

    To Be Continued...

  • 相关阅读:
    深入理解java虚拟机(7)---线程安全 & 锁优化
    深入理解java虚拟机(6)---内存模型与线程 & Volatile
    java注解框架
    敏捷软件开发---闲话敏捷
    深入理解java虚拟机(5)---字节码执行引擎
    龙应台写给儿子安德烈的信
    wojilu中的路由
    如何使用豆约翰博客备份专家批量下载新浪微博
    haha
    http://www.jsbreakouts.org/---各种html5框架实现打砖块游戏 breakout
  • 原文地址:https://www.cnblogs.com/liuyoung/p/7868458.html
Copyright © 2011-2022 走看看