重构心法修炼第三层:简化条件表达式

9.1  分解条件表达式

        如果有一个非常复杂的条件(if--then--else),可以将 if  then  else 三个段落中分别提炼出独立的函数。

        if 语句若有多个条件,按其意图抽取函数,并按意图命名,则代码可读性将大大提升。 then 与 else 段落的代码也一样可抽取。提炼出来的函数可读性也更高一些,它看上去就像一段注释那样清楚明白。

        if( isSummer() )    return summerPrice() ;  

        else   return  winterPrice();

9.2  合并条件表达式

        多个条件返回同样的检查结果,则可将这些条件语句合并为一个条件表达式。

        用逻辑运算符进行连接,并可将此条件表达式抽取为一个方法。

        一系列卫语句都得到相同的结果,可将这些卫语句合并为一个条件表达式,并将这个表达式提炼为一个函数。

        if(  a == 0 )  return 0 ;

        if(  b == 0 )  return 0 ;

        if(  c == 0)   return 0 ;

        doSomething();

改为

       if(  isZero()  ) return  0 ;

       doSomething();

       boolean  isZero()  {   return a == 0 || b == 0 || c == 0 }

         逻辑与可以使用三目运算符来合并分支。

  if( a > 0) {

       if ( b > 0 )

            return 1 ;

 return 0.5 ;

可重构为

    return  a > 0 && b > 0 ? 1 : 0.5 ;

9.3  合并重复的条件片段

        各个分支中若有相同功能的代码,则将其抽取并搬移到个分支的外面。

        都有的代码说明不随分支变化而变化,就不应该出现在分支中。

        重复代码在分支开始,将其搬到条件表达式之前。同理,重复代码在分支之后,可将其搬到条件表达式之后。

        如果重复代码在条件表达式中间,那么可以尝试将其移动到条件表达式的起始处或者末尾处,再进行搬移出去。

 if (  isA () )   {funA() ;  funC();}

 if (isB())  {funB() ;  funC();}

 可重构为

if (  isA () ){   funA() ;}

if (isB()) {    funB() ; }

funC();

9.4  移除控制标记

        尽量不要使用控制标记,在循环中使用break或者continue结束循环。

        如果不在循环中,找到程序的结束点,比如我的目标是某个IF条件,那么就在这个IF条件成立时,使用return结束当前的程序。

9.5  使用卫语句

        将所有非正常的逻辑提炼到条件表达式之前。这样的话,可以过滤一些罕见的情况,并突出显示我们的正常逻辑。

    if(  _isDead  ) return  deadAmount();

    if( _isSeparted) return  separatedAmount();

    if( _isRetired)  return  retiredAmount();

    return  normalPayAmount();

        其实就是把一些比较罕见的或者说不正常的情况提炼到函数起始处,对这些非正常的情况进行检查。

        如果不对这些情况进行检查,大量采用 if else 语句的话,很可能会让人难以看清正常的执行路径。

        使用卫语句的精髓就是,给某条分支特别的重视。如果使用 if - else 语句,就表明对 if 分支 与 else 分支的重视程度是相同的。如果两条分支都是正常的话,那么就使用 if - else 语句。如果某些情况十分罕见,就应该使用卫语句进行单独的检查,并在条件为真的时候,立刻从函数中返回。

        还有一种重构手法是,将条件反转。

        正常逻辑的执行条件是  A > 0  B>0  C>0  。那么可以如此重构。

    if ( A < = 0 ) return ;

    if  ( B < = 0 ) return ;

    if ( C < = 0 )  return ;

    doSomething();

9.6  使用多态取代条件表达式

        如果有一个条件表达式,它根据对象类型的不同而选择不同的行为。

        将这个条件表达式的每个分支放进一个子类内的重写函数中,然后将原函数申明为抽象函数。

        当前对象持有抽象状态类型引用,将不同的状态设计为子类。为当前对象设置好相应的状态后,可将当前对象的相关功能方法委托给状态子类对象去做。例如,员工的职位类型有非常多种,那么就创建一个员工职位类型的抽象对象,并让员工类持有这个抽象职位类型的引用,再为这个抽象职位类型创建设值方法。接着,为抽象职位类型创建子类,并实现相关计算薪资的办法。最后,在员工对象中,将计算薪资的方法委托给接收到的职位类型状态对象。

        经典代码参考:重构——以多态取代条件表达式(状态模式)

public class Employ {
    /**
     * 核心:当前对象持有抽象状态类型对象
     * 即员工对象持有一个抽象的员工状态类型对象引用
     * 设计一个取值方法,即setEmployType方法获取 抽象员工状态 的子类对象
     */
    private EmployType employType;

    public int getBaseWage() {
        return 2000;
    }

    public int getBonus() {
        return 500;
    }

    private void setEmployType(EmployType employType) {
        this.employType = employType;
    }

    /**
     * 将员工计算工资的方法 委托给 员工状态类型
     * 方法参数为 this
     * 是为了让 员工状态类型的子类对象
     * 可以使用当前员工对象的 getBaseWage()与 getBonus方法
     *
     * @return
     */
    public int caculateMoney() {
        return employType.caculateMoney(this);
    }
}

         

 

       

 

      

posted @ 2022-07-17 12:15  小大宇  阅读(27)  评论(0编辑  收藏  举报