Summary: 函數中的條件邏輯令人難以看清正常的執行路徑。使用衛語句表現全部特殊狀況。java
動機:程序員
條件表達式一般有兩種表現形式。第一種形式是:全部分支都屬於正常行爲。第二種形式則是:條件表達式提供的答案中只有一種是正常行爲,其餘都是不常見的狀況。編程
這兩類條件表達式有不一樣的用途,這一點應該經過代碼表現出來。若是兩條分支都是正常行爲,就應該使用如if…else…的條件表達式;若是某個條件極其罕見,就應該單獨檢查該條件,並在該條件爲真時馬上從函數中返回。這樣的單獨檢查經常被稱爲「衛語句」(guard clauses)編程語言
Replace Nested Conditional with Guard Clauses的精髓就是:給某一條分支以特別的重視。若是使用if-then-else結構,你對if分支的重視是同等的。這樣的代碼結構傳遞給閱讀者的消息就是:各個分支有一樣的重要性。衛語句就不一樣了,它告訴閱讀者:「這種狀況很罕見,若是它真地發生了,請作一些必要的整理工做,而後退出。」函數
「每一個函數只能有一個入口和一個出口」的觀念,根深蒂固於某些程序員的腦海裏。當咱們處理他們編寫的代碼時,常常須要使用Replace Nested Conditional with Guard Clauses。現金的編程語言都會強制保證每一個函數只有一個入口,至於「單一出口」規則,其實不是那麼有用。保持代碼清晰纔是最關鍵的:若是單一出口能是這個函數更清楚一度,那麼就使用單一出口;不然就沒必要這麼作測試
作法:spa
1.對於每一個檢查,放進一個衛語句。code
衛語句要不就從函數中返回,要不就拋出一個異常。orm
2.每次將條件檢查替換成衛語句後,編譯並測試。get
若是全部衛語句都致使相同結果,請使用Consolidate Conditional Expressions
範例:
想象一個薪資系統,其中以特殊規則處理死亡員工、駐外員工、退休員工的薪資。這些狀況不常有,但的確偶爾會出現。
假設咱們在這個系統中看到下列代碼:
double getPayAmount(){ double result; if(_isDead){ result = deadAmount(); }else{ if(_isSeparated){ result = separatedAmount(); }else{ if(_isRetired){ result = retiredAmount(); }else{ result = normalPayAmount(); } } } return result; }
在這段代碼中,非正常狀況的檢查掩蓋了正常狀況的檢查,因此應該用衛語句來取代這些檢查,以提升程序清晰度。咱們能夠逐一引入衛語句。讓咱們從最上面的條件檢查動做開始,:
double getPayAmoutn{ double result; if(_isDead){ return deadAmount(); } if(_isSeparated){ result = separatedAmount(); }else{ if(_isRetired){ result = retiredAmount(); }else{ result = normalPayAmount(); } } } return result }
而後繼續下去,仍然一次替換一個檢查動做,直到最後一個:
double getPayAmoutn{ double result; if(_isDead){ return deadAmount(); } if(_isSeparated){ return separatedAmount() } if(_isRetired){ return retiredAmount(); } result = normalPayAmout(); return result; }
此時,result變量已經沒有價值了,因此咱們把它刪掉:
double getPayAmoutn{ double result; if(_isDead){ return deadAmount(); } if(_isSeparated){ return separatedAmount() } if(_isRetired){ return retiredAmount(); } return normalPayAmout(); }
嵌套條件代碼每每由那些深信「每一個函數只能有一個出口」的程序員寫出。我發下那條規則實在有點太簡單粗暴了。若是對函數剩餘部分再也不有興趣,固然應該馬上退出。引導閱讀者去看一個沒有用的else區段,只會妨礙他們的理解。