改善代碼設計 —— 簡化條件表達式(Simplifying Conditional Expressions)

作者: Create Chen  來源: 博客園  發布時間: 2011-05-31 21:57  閱讀: 2640 次  推薦: 0   原文鏈接   [收藏]  

  系列博客

      1. 改善代碼設計 —— 優化函數的構成(Composing Methods)

      2. 改善代碼設計 —— 優化物件之間的特性(Moving Features Between Objects)

      3. 改善代碼設計 —— 組織好你的數據(Composing Data)

      4. 改善代碼設計 —— 簡化條件表達式(Simplifying Conditional Expressions)

      5. 改善代碼設計 —— 簡化函數調用(Making Method Calls Simpler)

      6. 改善代碼設計 —— 處理概括關系(Dealing with Generalization)

  1. Decompose Conditional (分解條件式)

  解釋:

      "復雜的條件邏輯" 是導致復雜性上升最常見的地方, "條件表達式中堆積的計算過程", "條件式表達得不簡潔"等等都是造成復雜的原因. Decompose Conditional 用于將這些復雜的元素從條件表達式中分離出去, 僅在條件表達式中調用簡潔的函數.

      這樣做帶來的直接好處是減少重復, 而且代碼的可讀性提高了.

  沖動前:

 
if (date.After(SUMMER_START) && date.Before(SUMMER_END))
charge
= days * _price + _summerServiceTip;
else
charge = days * _price;

  沖動后:

 
if (date.IsSummer())
charge
= SummerCharge(days);
else
charge = WinterCharge(days);

  2. Consolidate Conditional Expression (合并條件式)

  解釋:

      如果代碼中有一連串的 if 檢查語句, 檢查語句中的條件不相同, 但最終的行為都是一樣的. 對于這樣的情況, 應該使用 "邏輯與" 和 "邏輯或" 將它們合并成一個條件表達式, 如果嫌這個合并條件后的表達式太羅嗦, 你還可以將這個表達式提取成一個函數.

  沖動前:

 
if (computer.CPU != "T6670")
return false;
if (computer.RAM != "1.00GB")
return false;
if (computer.SytemType != "32-bit Operating System")
return false;
//other compution

  沖動后:

 
if ((computer.CPU != "T6670") || (computer.RAM != "1.00GB") || (computer.SytemType != "32-bit Operating System"))
return false;
//other compution

      你還可以將 if 里長長的條件表達式提取成一個方法, 如 bool IsStandard(Computer computer), 這樣在原來的 if 語句中只需要調用這個方法即可微笑

  3. Consolidate Duplicate Conditional Fragments (合并重復的條件片段)

  解釋:

      如果條件式的每個分支上都有同樣一段代碼, 如果這段代碼對條件分支在執行這段代碼后執行后面的代碼沒有影響,  請將這段代碼移到條件式的外面.

  沖動前:

 
if (date.IsSummer())
{
charge
= days * _price + _summerServiceTip;
PrintDetail();
}

else
{
charge
= days * _price;
PrintDetail();
}

//other compution

  沖動后:

 
charge = days * _price;

if (date.IsSummer())
charge
+= _summerServiceTip;

PrintDetail();

//other compution

  4. Remove Control Flag (移除控制標志)

  解釋:

      很多代碼里執行一個 for 或者 while 循環用于尋找一個數組里特點的元素, 很多時候在循環開頭就執行控制標志的檢查, 滿足檢查條件就繼續執行循環查找元素. 如果這一次查找到了想要的元素, 就更改控制標志的值, 讓它下次被檢查出不符合條件, 從而循環結束.

      這并不是一個很好的做法, 使用諸如 break, continue, return 語句會讓你的代碼意圖更加直接, 更加明顯.

  沖動前:

 
for (int i = 0; i < suspects.Length; i++)
{

if (!found)
{

if (suspects[i].Name == guessName)
{
sendAlert();
found
= true;
}
}
}

  沖動后:

 
for (int i = 0; i < suspects.Length; i++)
{

if (suspects[i].Name == guessName)
{
sendAlert();

break;
}
}

  5. Replace Nested Conditional with Guard Clauses (以衛語句取代嵌套條件式)

  解釋:

      許多程序員覺得函數應該只有一個出口 (return), 結果導致函數中的條件邏輯 (Conditional Logic) 本來完全可以終止下面的代碼繼續執行 (因為沒有必要), 結果卻只在函數最后 return, 使人難以看清程序的執行路徑.

      Replace Nested Conditional with Guard Clauses 用來解決這個問題, 它能帶給代碼可讀性的提高, 還有性能上一點點的優化.

  沖動前:

 
double charge;

if (IsSummer(date))
{

//...
SummerCharge(charge);
}

else
{
//...
WinterCharge(charge);
}


return charge;

  沖動后:

 
double charge;

if (IsSummer(date))
{

//...
SummerCharge(charge);

return charge;
}

else
{
//...
WinterCharge(charge);

return charge;
}

  6. Replace Conditional with Polymorphism (以多態取代條件)

  解釋:

      這條重構手法常常用于消除函數中長長的 switch-case 語句. 雖然寫一個個的子類比較繁瑣, 但隨著項目的進行, 好處會體現出來的.

  沖動前:

 
public double Salary(Employee employee)
{
switch(employee.Type):
{

case Employee.Engineer
{

//...
}

case Employee.Salesman:
{

//...
}

//...
default:
{

//...
}
}
}

  沖動后:

 
public abstract double Salary(Employee employee);

class Engineer : Employee
{

public override double Salary(Employee employee)
{

//...
}
}
class Salesman : Employee
{

public override double Salary(Employee employee)
{

//...
}
}

  7. Introduce Null Object (引入 Null 對象)

  解釋:

      如果代碼中出現很多判斷某值是不是為 null , 諸如 if (XXX != null) {//...} else {//...} 這樣的情況, 可以考慮使用 Introduce Null Object 重構手段. 這個手段其實并不難以理解, 可以簡單理解成為某一個物件在為空狀態下設定默認的值域和行為, 可以建立一個子類, 繼承父類中需要對 "為空" 情況下做出響應的虛函數或者值域. 它是 Null Object 設計模式里的最基礎最常見的手段.

  8. Introduce Assertion (引入斷言)

  解釋:

      嚴格上說, 引入斷言并不是為了簡化條件表達式, 它主要是為了代替條件表達式上面的注釋, 通常這樣的注釋用來解釋下面的條件表達式是基于什么樣的假設之上的. 通常經過一系列的測試, 發現所寫的斷言在任何情況下都是正確的, 在系統發布的時候可以把它們全部刪除掉.

      在 C# 中引入斷言使用 Debug.Assert() 方法, 如果一切假設都是正確的, 則代碼會順利的進行.

  沖動前:

 
//index should between 0 to 10
return (customers[index] == "James") ? true : false;

  沖動后:

 
Debug.Assert((index>=0)&&(index <= 10), "Error", "index should between 0 to 10");
return (customers[index] == "James") ? true : false;

  如果斷言錯誤, 在運行的時候會有一個消息框給予錯誤信息的提示.

0
0
 
標簽:重構
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()