過多if - else 的問題, 以及策略模式 + 反射解決方法

clnsx發表於2021-03-10
  1. 策略模式解決if - else 的程式碼

業務場景:

外包企業的審批人需要審批打卡的場景;

審批人分為多種不同的級別,多種級別中具有方式相同但是內容不同的操作:審批。

原來場景:

有前端傳來審批人蔘數,使用if-else 來判斷該審批人的級別屬於哪一個級別,執行相應的審批方法。每一個審批方法寫在了業務類底,命名採用1級審批,2級審批---等等的命名方式來命名。

問題:if - else 邏輯複雜,不易閱讀,函式中審批能抽象的地方未抽象,

兩個核心問題:test測試非常麻煩,新增審批人員需要對程式碼進行修改,違背開閉原則。

解決過程:

  1. 抽象審批中的原子操作的程式碼,比如查詢對應級別所審批的同學名單。程式碼變得好看一些,但是任然未解決,if - else 和 多個 審批方法的實現。

  2. 嘗試策略模式

    1. 使用策略模式將每個級別的使用者抽象起來

    2. package strategy;
      
      
      
      public class Main {
          public static void main(String[] args) {
              if (LevelEnum.LEVEL1.equals(1)) {
                  SupervisorControl supervisorControl = new SupervisorControl(new Supervisor1());
                  supervisorControl.execute(1);
              }
              if (LevelEnum.LEVEL2.equals(2)) {
                  SupervisorControl supervisorControl = new SupervisorControl(new Supervisor2());
                  supervisorControl.execute(2);
              }
              if (LevelEnum.LEVEL3.equals(3)) {
                  SupervisorControl supervisorControl = new SupervisorControl(new Supervisor3());
                  supervisorControl.execute(3);
              }
          }
      }
      
      package strategy;
      
      public enum LevelEnum {
          LEVEL1, LEVEL2, LEVEL3
      }
      
      package strategy;
      
      public interface Supervisor {
          void examine(int supervisorId);
      }
      
      package strategy;
      
      public class Supervisor1 implements Supervisor {
          public void examine(int supervisorId) {
              System.out.println("去做一些和1級supervisor相關的工作");
          }
      }
      
      package strategy;
      
      public class Supervisor2 implements Supervisor {
          public void examine(int supervisorId) {
              System.out.println("去做一些和2級supervisor相關的工作");
          }
      }
      
      package strategy;
      
      public class Supervisor3 implements Supervisor {
          public void examine(int supervisorId) {
              System.out.println("去做一些和3級supervisor相關的工作");
          }
      }
      
      package strategy;
      
      public class SupervisorControl {
          Supervisor supervisor;
          public SupervisorControl(Supervisor supervisor) {
              this.supervisor = supervisor;
          }
          public void execute(int id) {
              supervisor.examine(id);
          }
      }
      

解決方法:

  1. 混合使用策略模式和反射來解決
package strategy;



public class Main {
    public static void main(String[] args) {
//        if (LevelEnum.LEVEL1.equals(1)) {
//            SupervisorControl supervisorControl = new SupervisorControl(new Supervisor1());
//            supervisorControl.execute(1);
//        }
//        if (LevelEnum.LEVEL2.equals(2)) {
//            SupervisorControl supervisorControl = new SupervisorControl(new Supervisor2());
//            supervisorControl.execute(2);
//        }
//        if (LevelEnum.LEVEL3.equals(3)) {
//            SupervisorControl supervisorControl = new SupervisorControl(new Supervisor3());
//            supervisorControl.execute(3);
//        }
        String packageName = Supervisor1.class.getPackage().getName();
        String supervisorName = packageName + "." + "Supervisor" + "2";
        try {
            Class<?> clazz = Class.forName(supervisorName);
            Supervisor supervisor = (Supervisor) clazz.newInstance();
            supervisor.examine(1);
        } catch (Exception e) {
            System.out.println(e);
        }

    }
}

注意

class.forName() 需要傳入的格式是"包名.類名"。如果找不到包名則會報ClassNotFoundException

可以通過class.getPackage來獲取包名。


到此我們解決了if - else 很多的問題,並且解決了需要侵入程式碼修改的問題,如果新增supervisor的級別,只需要和前端達成一致,後臺繼續寫一個supervisor4物件即可。

為什麼解決了test難的問題

對於test來說,每一個If-else 都需要我們去驗證,這其實就是兩個test, if 一個 else一個,如果有很多if - else,想要保證高的test覆蓋率,就會非常頭痛。

然而我們用策略模式 和 反射來解決,只需要,對主邏輯一個test,每一個實現方法做一個test即可。

至此,所有問題都解決了,程式碼一片光明。

相關文章