代碼重構之消除分支結構

一. 爲何要消除 if-else

當寫下第一行 if-else 時,就爲發展成幾十個 if-else 埋下了伏筆.javascript

當一個 if-else 有可能臃腫時,那麼它必定會臃腫.  --墨菲

一個例子:php

$userType = '';
if ($userTypeID == 1){
    $userType = 'Admin';
}elseif($userTypeID == 2){
    $userType = 'Corporate Customers';
}

看起來很是美妙,簡潔.可是當系統慢慢複雜化,角色不斷的豐富,就變成這樣的代碼:java

$userType = '';
if ($userTypeID == 1){
    $userType = 'Admin';
}elseif($userTypeID == 2){
    $userType = 'Corporate Customers';
}elseif($userTypeID == 3){
    $userType = 'Editorial Users';
}elseif($userTypeID == 4){
    $userType = 'Photographers';
}elseif($userTypeID == 5){
    $userType = 'Vendors';
}

來個極端的例子:mysql

圖片描述

能夠說很是可怕了.git

二. 如何消除 if-else

消除這種條件裏都是定值的 if-else 咱們能夠採用 查表法 來消除.github

經過容器將對應的關係進行存儲。經過運算得出相應關係中的其中一方的結果,再經過這個結果去容器中找對應的另外一個內容

通俗的說,就是創建一個對象或者數組的 hash 表, key 值存儲條件判斷, value 存儲符合該條件判斷的邏輯處理.
好比上面的代碼能夠寫成:算法

const USER_TYPE_ADMIN = 1;
  const USER_TYPE_CORPORATE = 2;
  const USER_TYPE_EDITORIAL = 3;
  const USER_TYPE_PHOTOGRAPHERS = 4;
  const USER_TYPE_VENDORS = 5;

  public function getUserTypeName($key = null){
    $data = array(
      self::USER_TYPE_ADMIN => 'Admin',
      self::USER_TYPE_CORPORATE => 'Corporate Customers',
      self::USER_TYPE_EDITORIAL => 'Editorial Users',
      self::USER_TYPE_PHOTOGRAPHERS => 'Photographers',
      self::USER_TYPE_VENDORS => 'Vendors',
    );
    return $key === null ? $data : (isset($data[$key]) ? $data[$key] : '');
  }

這樣,上面的一大段的 if-else 就一行代碼搞定: $userType = User::getUserTypeName($userTypeID)sql

用 JavaScrip 語言來描述:數組

let userTypeObj = {
    1: 'Admin',
    2: 'Corporate Customers',
    3: 'Editorial Users',
    4: 'Photographers',
    5: 'Vendors',
};

let userTypeName = userTypeObj[userTypeID];

上面的例子只是不一樣的 userTypeID 獲取不一樣的 userTypeName. 考慮更復雜的狀況,當不一樣的 userTypeID 時進行不一樣邏輯處理.curl

if (userTypeID == 1) {
    //Todo ...
} else if(userTypeID == 2) {
    //Todo ...
} else if(userTypeID == 3) {
    //Todo ...
} else if(userTypeID == 4) {
    //Todo ...
}

這個時候能夠把裏面的邏輯處理代碼抽出來爲一個函數:

let userTypeObj = {
    1: () => {
        //Todo...
    },
    2: () => {
        //Todo...
    },
    3: () => {
        //Todo...
    },
    4: () => {
        //Todo...
    },
};

userTypeObj[userTypeID]();

以上代碼也能夠以 php 的可變變量/面向對象的多態特性來實現.

缺點:查表法的實現,要作越界檢查,還要確保下標計算不會重複,若是使用面向對象的多態特性來實現,也有策略類增多等問題.

這個查表法的實現,實際上是策略模式的思想.

策略模式指的是定義一系列的算法,把他們一個個的封裝起來.策略模式的目的就是將算法的使用與算法的實現分離開來.

更多關於策略模式的講解,請看這裏

三. 總結

if-else 固然是有用的,好比 mysql 連接, curl 的返回碼等等.當開始寫的時候,只有一個 if-else ,咱們能夠不去消除,可是當要寫到第三個第四個分支,或者每一個條件分支裏面都有大段大段的邏輯處理代碼,咱們就要考慮消除它了.

當條件語句不是定值,而是範圍值的時候,如何消除 if-else 求教:

if(x < 30){
    //todo
}else if(x >= 30 ){
    //todo
}
相關文章
相關標籤/搜索