博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

重构之简化条件表达式

Posted on 2011-06-14 21:18  zhangweia  阅读(219)  评论(0编辑  收藏  举报

      条件逻辑有可能十分复杂,因此本章提供一些重构手法,专门用来简化它们。其中一项核心重构就是Decompose Conditional,可将一个复杂的条件逻辑分成若干小块。这项重构很重要,因为它使逻辑和操作细节的分离。

     本章的其余重构手法可用以处理另一些重要问题,如果你发现代码中的多处测试有相同的结构,应该实施Consolidate Conditional Expression,如果条件代码中有任何重复,可以运用Consolidate Duplicate Conditional Fragment 将重复成分去掉。

      较之于过程化程序而言,面向对象因为多态的机制可以简化条件行为的细节

1. Replace Nested Condition with Guard Clauses(以卫语句

取代嵌套条件表达式) 

        Clauses[klɔ:zis] :字句      Guard[ga:d]: 守卫、看守    Nesting: 嵌套

        范例:

               想象一个薪酬系统,其中以特区规则处理死亡、驻外、退休员工的薪资,这些情况不常有,但偶然会出现

         常规编码:

   1:      private double getPlayAmount(){
   2:          double result;
   3:          if(_isDead){
   4:              result = deadAmount();
   5:          }else{
   6:              if(_isSeparated){
   7:                  result = separatedAmount();
   8:              }else {
   9:                  if(_isRetired){
  10:                      result = retiredAmount();
  11:                  }else {
  12:                      result = normalAmount();
  13:                  }
  14:              }
  15:          }
  16:          return result;
  17:      }
 
   分析: 条件表达式通常有两种表现形式。第一种:所有的分支都属于正常行为,应该用
             if..else表达出来。第二种:条件表达式提供的答案中只有一种是正常行为,其
             他都是不常见的行为。此时就要单独检查该条件,并在该条件为真时立刻从函数
             中返回,这种单独检测常常为称为“卫语句”通过分析题意,我们知道该函数主
             体是付普通情况的工资,而死亡、驻外、退休属于特区情况,因此我们把他们做
             为卫语句处理,修改后为:
      
   1:      private double getPlayAmount(){
   2:          
   3:          if(_isDead){
   4:              return deadAmount();
   5:          }
   6:          
   7:          if(_isSeparated){
   8:              return separatedAmount();
   9:          }
  10:          
  11:          if(_isRetired){
  12:              return retiredAmount();
  13:          }
  14:   
  15:          return normalAmount();
  16:      }
 

     2. Decompose Conditional (分解条件表达式) 

        decompose [ˌdi:kəmˈpəuz] :分解、腐烂

         -----你有一个复杂的条件语句(if、then、else),从if ,then,else三个段落中分别提炼出独立函数

         假设我要计算购买某样商品的总价(总价=数量 * 单价),而这个商品在冬季和夏季的单价是不同的。

    if(data.before(SUMMER_START) || data.after(SUMMER_END)){
        charge = quantity * _winterRate ;
    }else{
        charge = quantity * _summerRate
    }

        分析:复杂的条件逻辑是最常导致复杂度上升的原因之一,常见的做法是1) 将if段提炼出来,构成一个独立的函数  2)将then和else段提炼出来构成一个独立的函数

        修改后的代码为:

    if(notSummer(data)){
        charge = winterCharge(quantity);
    }else{
        charge = summerCharge(quantity);
    }
    
    private boolean notSummer(Data data){
        return data.before(SUMMER_START) || data.after(SUMMER_END);
    }
    
    private double summerCharge(int quantity){
        return quantity * _summerRate;
    }
    
    private double winterCharge(int quantity){
        return quantity * _winterRate;
    }

     通过以上的简化,条件表达式逻辑块就像代码注释一样清晰、明了

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

       ----你有一系列的条件测试,都得到相同的结果,将这些测试合并为一个条件表达式,并将这个条件表达式提炼为一个独立的函数

       示例:

    double disabilityAmount(){
        if(_seniority < 2){
            return 0;
        }
        if(_months > 12){
            return 0;
        }
        if(_isPartTime){
            return 0;
        }
    }

      分析:有时候你会发现一连串的检查条件,虽然条件各不相同,但是最终行为却一致,这种情况一般是用“逻辑与”或者“逻辑或”把他们合并为一个条件表达式,使代码更清楚。 合并后

    double disabilityAmount(){
        if(isNotAbility()){
            return 0
        }
    }
    
    boolean isNotAbility(){
        return ((_seniority < 2) || (_months > 12) || _isPartTime)
    }
4. Consolidate Duplicate Conditional Fragements(合并重复的
    条件片段)
       ---在条件表达式的每个分支上有着相同的一段代码
    if(isBook){
        total = price * 0.95;
        send();
    }else{
        total = price * 0.5;
        send();
    }
    分析: 针对这种情况,应该将重复的代码搬移到条件表达式的外面,这样代码才能够更加清
          楚的表明那些东西随条件的变化而变化,那些东西保持不变
    if(isBook){
        total = price * 0.95;
    }else{
        total = price * 0.5;
    }
    send();

5. Replace Conditional with Polymorphism(以多态取代条件

表达式)

    如果需要根据对象的不同类型而采取不同的行为,多态使你不需要编写明显的条件表达式。比如重构第一章我们提到的电影分儿童、新片、普通片。这三种片都是电影的不同类型,我们可以定义一个电影的抽象类,然后利用多态的性质,让不同的类型的电影去继承,这样我们就可以去掉多余的条件判断