重构手法之简化条件表达式【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...

时间: 2024-11-07 22:16:42

重构手法之简化条件表达式【1】的相关文章

重构摘要9_简化条件表达式

<重构-改善既有代码的设计>Martin Fowler 摘要: 第九章 简化条件表达式 Decompose Conditinal 分解条件表达式 你有一个复杂的条件(if-then-else)语句 从三个段落中分别提炼出独立函数 Consolidate Conditional Expression 合并条件表达式 你有一系列条件测试,都得到相同结果 将这些测试合并成为一个条件表达式,并将这个条件表达式提炼成为一个独立函数 检查用意更清晰,有时也不用这么做 Consolidate Duplica

【重构.改善既有代码的设计】9、简化条件表达式

简化条件表达式 Decompose Conditional(分解条件式) 你有一个复杂的条件(if-then-else)语句. 从if.then.else 三个段落中分别提炼出独立函数. 分解为多个独立函数,根据每个小块代码的用 途,为分解而得的新函数命名,并将原函数中对应的代码替换成「对新建函数的调用」,从而更清楚地表达自己的意图. 对于条件逻辑,[将每个分支条件分解,形成新函数」还可以给你带来更多好处:可以突出条件逻辑,更清楚地表明每个分支的作用,并且突出每个分支的原因. Consolida

重构改善既有代码的设计--简化条件表达式

一 简化条件表达式 这个是几乎所有的工程都会存在的问题,不当的条件表达式造成代码的冗余. 下面我们列出普遍的问题,并给出一般的应对方法. [1]条件判断过长,表达不清晰. if((i!=0&&i == m_nDClickIndex[1])&&(m_nDClickIndex[1]!=m_nDClickIndex[0])) { .... } 解决办法:将很长的判断式子封装成函数或者定义成宏.并以一个清晰表达意图的名字命名,这种做法在现代oop语言中很常见,比如 java c#

Simplifying Conditional Expressions(简化条件表达式)

1.Decompose Conditional(分解条件表达式) 2.Consolidate Conditional Expressions(合并条件表达式) 3.Consolidate Duplicate Conditional Fragments(合并重复的条件片段) 4.Remove Control Flag(移除控制标记) 5.Replace Nested Conditional with Guard Clauses(以卫语句取代嵌套条件表达式) 6.Replace Conditiona

学习重构(5)-简化条件表达式

1.Decompose Conditional (分解条件表达式)应用场景:你有一个复杂的条件(if-then-else)语句.从if.then.else三个段落中分别提炼出独立函数.示例:if (date.before(SUMMER_START) || date.after(SUMMER_END)) { charge = quantity * mWinterRate + mWinterServiceCharge;} else { charge = quantity * mSummerRate;

简化条件表达式之以卫语句取代嵌套条件表达式(Replace Nested Conditional With Guard Clauses)

函数中的条件逻辑使人难以看清正常的执行途径.使用卫语句表现所有特殊情况. 动机:条件表达式通常有2种表现形式.第一:所有分支都属于正常行为.第二:条件表达式提供的答案中只有一种是正常行为,其他都是不常见的情况. 这2类条件表达式有不同的用途.如果2条分支都是正常行为,就应该使用形如if…..else…..的条件表达式:如果某个条件极其罕见,就应该单独检查该条件,并在该条件为真时立刻从函数中返回.这样的单独检查常常被称为“卫语句”. Replace Nested Conditional with

【重构学习】08 条件表达式的重构

所谓条件表达式,就是分支语句,去掉分支语句咯 1.分解条件表达式 修改点:你有一个复杂的条件语句(就是if else语句) 做法:将条件表达式的三个部分分别提炼出独立函数 即 if (A部分) { B部分; } else { C部分; } 这三个部分都提炼成函数就好了. 2.合并条件表达式 修改点:你有一系列测试,都得到相同结果 做法:将这些测试合并成一个条件表达式,并将这个表达式提炼成一个独立函数 3.合并重复的条件片段 修改点:在条件表达式的每个分支上有着相同一段代码 做法:将这段重复代码搬

简化条件表达式之移除控制标记(Remove Control Flag)

在一系列布尔表达式中,某个变量带有“控制标记’的作用.以break或return语句取代控制标记. 动机:在一系列条件表达式中,常常会看到用以判断何时停止条件检查的控制标记.这样的标记带来的麻烦超过了它所带来的便利.人们之所以会使用这样的控制标记,因为结构化编程原则告诉他们:每个子程序只能有一个入口和出口.“单一出口“原则会让你在代码中加入让人讨厌的控制标记,大大降低条件表达式的可读性.这就是编程语言提供break和continue语句的原因:用它们跳出复杂的条件语句.去掉控制标记所产生的效果往

简化条件表达式

1.分解条件表达式:a.将判断条件独立函数:b.将分支段落独立函数: 2.合并条件表达式:a.使用逻辑或/与:b.三元表达式 3.合并重复的代码片段 4.移除控制标记:a.找出对标记变量赋值的语句,代之break或continue:b.extract method,以return返回控制标记 5.以卫语句取代嵌套条件表达式: 精髓:给某一条分支以特别的重视 比较:if-then-else则是同等重要 方式:将条件反转,最后考虑去除零时变量 6.以多态取代条件表达式: a.extract meth