• 《重构:改善既有代码的设计》读书笔记4 简化条件表达式


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

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

    1 if(data.before(SUMMER_START)||data.after(SUMMER_END))
    2     charge=quantity*_winterRate+_winterServiceCharge;
    3 else charge=quantity*_summerRate;
    4 
    5 -->
    6 
    7 if(notSummer(date))
    8     charge=winterCharge(quantity);
    9 else charge=summerCharge(quantity);

    复杂的条件逻辑是导致复杂度上升的地点之一,编写代码来检查不同的条件分支、昨不同的事会得到一个很长的函数。大型函数自身就会使代码的可读性下降,而条件逻辑会使代码更难阅读, 将每条分支分解成新函数,可以突出条件逻辑。

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

    一些列测试条件得到相同的结果,将这些测试合并为一个表达式。

    double disabillityAmount(){
        if(seniority<2)  return 0;
        if(isPartTime) return 0;
    }
    
    -->
    double disabillityAmount(){
    if(seniority<2||isPartTime)
        return 0;
    }
    
    -->
    double double disabillityAmount(){
    if(function())
    return 0
    }

    (3)Consolidate Duplicate Conditional Fragments(合并重复的条件片段)

    在条件表达式每个分支上有着相同的一段代码,将这段重复代码搬移到条件表达式之外。如果try 和catah 有重复代码 移到final区域。

    if(judge()){
        total = price * 0.5;
        send();
    }
    else{
        total = price * 0.8;
        send();
    }
    
    ==>
    if(judge()){
        total = price * 0.5;
    }
    else{
        total = price * 0.8;
    }
    
    send()

    (4)Remove Control Flag 移除控制标记

    在一系列布尔表达式中,某个变量带有控制标记的作用,以break或return语句取代控制标记。

    void checkSecurity(String[] people) {
          boolean found = false;
          for (int i = 0; i < people.length; i++) {
              if (! found) {
                 if (people[i].equals ("Don")){
                   sendAlert();
                   found = true;
                 }
                 if (people[i].equals ("John")){
                   sendAlert();
                   found = true;
                 }
              }
          }
      }
    
    --》
    
     void checkSecurity(String[] people) {
          boolean found = false;
          for (int i = 0; i < people.length; i++) {
              if (! found) {
                 if (people[i].equals ("Don")){
                   sendAlert();
                 break;
                 }
                 if (people[i].equals ("John")){
                   sendAlert();
                   found = true;
                 }
              }
          }
      }

    -->
     void checkSecurity(String[] people) {
          for (int i = 0; i < people.length; i++) {
              if (people[i].equals ("Don")){
                 sendAlert();
                 break;
              }
              if (people[i].equals ("John")){
                 sendAlert();
                 break;
              }
          }
      }

    例二 在这里,变量found 做了两件事:它既是控制标记,也是运算结果。遇到这种情况,我喜欢先把计算found 变量的代码提炼到一个独立函数中:
     void checkSecurity(String[] people) {
          String found = "";
          for (int i = 0; i < people.length; i++) {
              if (found.equals("")) {
                 if (people[i].equals ("Don")){
                   sendAlert();
                   found = "Don";
                 }
                 if (people[i].equals ("John")){
                   sendAlert();
                   found = "John";
                 }
              }
          }
          someLaterCode(found);
      }

    -->
     void checkSecurity(String[] people) {
          String found = foundMiscreant(people);
          someLaterCode(found);
      }
      String foundMiscreant(String[] people){
          String found = "";
          for (int i = 0; i < people.length; i++) {
              if (found.equals("")) {
                 if (people[i].equals ("Don")){
                   sendAlert();
                  return "Don";
                 }
                 if (people[i].equals ("John")){
                   sendAlert();
                   found = "John";
                 }
              }
          }
          return found;
      }
    即使不需要返回某值,你也可以使用语句来取代控制标记。这时候你只需 要一个空的return 语句就行了。

    (5)replace nested conditional with guard clauses 以卫语句取代嵌套条件表达式

    卫语句就是把复杂的条件表达式拆分成多个条件表达式,比如一个很复杂的表达式,嵌套了好几层的if - then-else语句,转换为多个if语句,实现它的逻辑,这多条的if语句就是卫语句.

     double getPayAmount() {
       double result;
       if (_isDead) result = deadAmount();
       else {
           if (_isSeparated) result = separatedAmount();
           else {
               if (_isRetired) result = retiredAmount();
               else result = normalPayAmount();
           };
       }
     return result;
     };
    =>
    
     double getPayAmount() {
       if (_isDead) return deadAmount();
       if (_isSeparated) return separatedAmount();
       if (_isRetired) return retiredAmount();
       return normalPayAmount();
     };

    (6) replace conditional with ploymorphism 以多态取代条件表达式

    你手上有个条件式,它根据对象型别的不同而选择不同的行为。

    将这个条件式的每个分支放进一个subclass 内的覆写函数中,然后将原始函数声明为抽象函数(abstract method)

    double getSpeed() {
          switch (_type) {
              case EUROPEAN:
                 return getBaseSpeed();
              case AFRICAN:
                 return getBaseSpeed() - getLoadFactor() * _numberOfCoconuts;
              case NORWEGIAN_BLUE:
                 return (_isNailed) ? 0 : getBaseSpeed(_voltage);
          }
          throw new RuntimeException ("Should be unreachable");
      }

    多态(polymorphism)最根本的好处就是:如果你需要根据对象的不同型别而采取不同的行为,多态使你不必编写明显的条件式(explicit conditional )。

    正因为有了多态,所以你会发现:「针对type code(型别码)而写的switch 语句」 以及「针对type string (型别名称字符串)而写的if-then-else 语句」在面向对象程序中很少出现。

     abstract class EmployeeType...
       abstract int getTypeCode();
    class Engineer extends EmployeeType... int getTypeCode() { return Employee.ENGINEER; }

     class Engineer...
       int payAmount(Employee emp) {
           return emp.getMonthlySalary();
       }

    class Salesman...
       int payAmount(Employee emp) {
           return emp.getMonthlySalary() + emp.getCommission();
       }
     class Manager...
       int payAmount(Employee emp) {
           return emp.getMonthlySalary() + emp.getBonus();
       }



     class EmployeeType...
       int payAmount(Employee emp) {
           switch (getTypeCode()) {
               case ENGINEER:
                  return emp.getMonthlySalary();
               case SALESMAN:
                  return emp.getMonthlySalary() + emp.getCommission();
               case MANAGER:
                  return emp.getMonthlySalary() + emp.getBonus();
               default:
                  throw new RuntimeException("Incorrect Employee");
           }
       }

    --》
    class Employee...
       int payAmount() {
           return _type.payAmount(this);
       }


     class EmployeeType...
       abstract int payAmount(Employee emp);
      
      abstract int getTypeCode()



    (9)Introduce null object 引入null 对象

     class NullCustomer extends Customer {
       public boolean isNull() {
           return true;
       }
     }
     class Customer...
       public boolean isNull() {
           return false;
       }
    或者
     interface Nullable {
       boolean isNull();
     }
     class Customer implements Nullable


    class Customer...
       static Customer newNull() {
           return new NullCustomer();
       }

    class Site...
       Customer getCustomer() {
           return (_customer == null) ?
               Customer.newNull():
               _customer;
       }

    
    
          Customer customer = site.getCustomer();
             BillingPlan plan;
             if (customer == null) plan = BillingPlan.basic();
             else plan = customer.getPlan();
    ...
             String customerName;
             if (customer == null) customerName = "occupant";
             else customerName = customer.getName();
    ...
             int weeksDelinquent;
             if (customer == null) weeksDelinquent = 0;
             else weeksDelinquent = customer.getHistory().getWeeksDelinquentInLastYear();

    --》
     Customer customer = site.getCustomer();
           BillingPlan plan;
           if (customer.isNull()) plan = BillingPlan.basic();
           else plan = customer.getPlan();
     ...
           String customerName;
           if (customer.isNull()) customerName = "occupant";
           else customerName = customer.getName();
     ...
           int weeksDelinquent;
           if (customer.isNull()) weeksDelinquent = 0;
           else weeksDelinquent = customer.getHistory().getWeeksDelinquentInLastYear();

    (9) 引入断言

    某一段代码需要对程序状态(state)做出某种假设。

    以assertion(断言)明确表现这种假设。

      double getExpenseLimit() {
          // should have either expense limit or a primary project
          return (_expenseLimit != NULL_EXPENSE) ?
              _expenseLimit:
              _primaryProject.getMemberExpenseLimit();
      }
    

    =>

      double getExpenseLimit() {
          Assert.isTrue (_expenseLimit != NULL_EXPENSE || _primaryProject != null);
          return (_expenseLimit != NULL_EXPENSE) ?
              _expenseLimit:
              _primaryProject.getMemberExpenseLimit();
      }
    这段代码包含了一个明显假设:任何员工要不就参与某个项目,要不就有个人开支限额。我们可以使用assertion 在代码中更明确地指出这一点
    
    
     
  • 相关阅读:
    N-Queens
    Pow(x, n)
    Maximum Subarray
    Spiral Matrix
    Jump Game
    Merge Intervals
    Insert Interval
    Length of Last Word
    Spiral Matrix II
    Amazon 面经
  • 原文地址:https://www.cnblogs.com/zdcsmart/p/12510205.html
Copyright © 2020-2023  润新知