2009-06-23 57 views
9

如果我有一個函數,有很多條件,組織它的最好方法是什麼?如果函數中的語句什麼是最好的方法

我擔心的是有人進入代碼並理解正在發生的事情。儘管這個例子很簡單,但假設條件非常複雜。

舉一個例子:

public void function(string value, string value2) 
{ 
    if (value == null) 
     return; 

    if (value2 == value) 
     DoSomething(); 
} 

public void function(string value, string value2) 
{ 
    if (value != null) 
    { 
     if (value2 == value) 
      DoSomething(); 
    } 
} 

public void function(string value, string value2) 
{ 
    if (value != null && value2 == value) 
     DoSomething(); 
} 

回答

8

組織條件並將它們放入方法。

例如替換此:

if(a& & n || c && (! d || e) && f > 1 && ! e < xyz) { 
     // good! planets are aligned. 
     buyLotteryTicket(); 
} else if(..... oh my ...) { 
} 

進入這個:

if(arePlanetsAligned()) { 
    buyLotteryTicket(); 
} else if(otherMethodHere()) { 
    somethingElse(); 
} 

這樣,它並沒有真正不管你用什麼風格(1,2或3),因爲if語句會清楚描述正在測試的條件。不需要額外的結構。

重點是使代碼更清晰和自我記錄。如果您使用的是OO編程語言,則可以使用對象來存儲狀態(變量),並避免創建需要5至10個參數的方法。

這些類似的問題:

Best way to get rid of nested ifs

Is there an alternative to this hyperidented code

第二個鏈接一個顯示轉變的可怕的所有人維護者噩夢成自我記錄代碼更完整和更復雜的方式。

它顯示瞭如何改造這個:

public String myFunc(SomeClass input) 
{ 
    Object output = null; 

    if(input != null) 
    { 
     SomeClass2 obj2 = input.getSomeClass2(); 
     if(obj2 != null) 
     { 
      SomeClass3 obj3 = obj2.getSomeClass3(); 
      if(obj3 != null && !BAD_OBJECT.equals(obj3.getSomeProperty())) 
      { 
       SomeClass4 = obj3.getSomeClass4(); 
       if(obj4 != null) 
       { 
        int myVal = obj4.getSomeValue(); 
        if(BAD_VALUE != myVal) 
        { 
         String message = this.getMessage(myVal); 
         if(MIN_VALUE <= message.length() && 
          message.length() <= MAX_VALUE) 
         { 
          //now actually do stuff! 
          message = result_of_stuff_actually_done; 
         } 
        } 
       } 
      } 
     } 
    } 
    return output; 
} 

到這一點:

if (isValidInput() && 
    isRuleTwoReady() && 
    isRuleTreeDifferentOf(BAD_OBJECT) && 
    isRuleFourDifferentOf(BAD_VALUE) && 
    isMessageLengthInRenge(MIN_VALUE , MAX_VALUE)) { 
      message = resultOfStuffActuallyDone(); 
} 
8

我更喜歡第一個選項 - fail fast是更清潔,更清晰,更易於閱讀和理解。

我知道這不是失敗,但這個概念仍然適用。我真的不喜歡嵌套if聲明。

+0

所有這三個例子實際上都失敗了,它們執行相同的空測試,並且如果value == null立即返回 – SpaceghostAli 2009-06-23 15:03:26

+0

如果您必須釋放任何資源,該怎麼辦?然後您需要在每個返回語句之前複製此清理代碼。我會說第二和第三選項要好得多。 – msvcyc 2009-06-23 15:08:43

+0

@msvcyc - RAII? – 2009-06-23 15:09:40

8

您可以查看防禦性編程以確保可以實現方法功能的合同。

public void function(string value, string value2) 
{ 
    if (string.IsNullOrEmpty(value1)) throw new ArgumentNullException("value1", "value 1 was not set"); 
    if (string.IsNullOrEmpty(value2)) throw new ArgumentNullException("value2", "value 2 was not set"); 

    DoSomething(); 
} 
+0

++對!防禦性failfast可能是最好的方式 – 2009-06-23 15:06:46

0

我喜歡第三種選擇,但這真的取決於語言。你假設在第三部分中,陳述的第一部分將失敗並且不執行第二部分。這是語言相關的。我知道大多數基於C的語言都是這樣做的,但是因爲你沒有指定一個潛在的問題。在那裏可能有一個我不知道沒有短路概念。

0

您事先有約代碼的可讀性思維的事實是成功的一半。

至於你的哪些例子最具可讀性,這是非常主觀的。

我給出的例子想法:

  • 我個人認爲,第一個例子是最容易 隨訪。
  • 最小化嵌套級別和/或 通常條件數 增強了可讀性。
  • 有人會反對從方法(如 例1)多 出口點,但我認爲T單獨 成爲一個問題,當 變得非常長的方法。這不是真的 這麼大的交易,如果你只是 檢查輸入和快速失敗。
0

我的偏好是第二種選擇。就我個人而言,當我閱讀這樣的代碼時,我會牢記我將輸入每個嵌套級別的條件。在第一個例子中,我可能會忘記第一個條件(value == null爲false)繼續保持。第三個也不錯,但我更喜歡第二個。

2

重構,它自己的功能。閱讀描述性函數名稱比一堆布爾表達式更好。

// leave complex conditional code out, so that we can focus on the larger problem in the function 
public void function(string value, string value2) 
{ 
    if (MyDescriptiveTestName) 
    { 
     DoSomething(); 
    } 
} 

// encapsulate complex conditional code so that we can focus solely on it. 
private bool MyDescriptiveTestName(string value, string value2) 
{ 
    if (value != null && value2 == value) 
    { 
     return true; 
    } 
    return false; 
} 
2

我可以用羅伯特C.馬丁提供了一個很大的組試探寫可讀和建議書Clean Code可維護的代碼。

現在另一種選擇是將條件解壓縮到另一個私有函數中,並將其命名爲描述您的意圖。它不提供的代碼工作也很好,因爲它是通用的,但它會看起來像:

public void function(string value, string value2) 
{ 
    if (valuesAreValidAndEqual(value, value2)) 
    { 
     DoSomething(); 
    } 
} 

private void valuesAreValidAndEqual(string value, string value2) 
{ 
    return value != null && value2 == value; 
} 

顯然,這是比較有用的,如果變量名和函數名都與您的域名。

0

事實上,你在一個函數中有很多的語句是一個標誌,該函數應該被分成更小的語句。

沒有最好的方式來陳述陳述,我認爲答案是主觀的。

0

清晰度往往是一個難以判斷的質量。當你寫一段代碼時,對你來說很清楚的事情可能對其他人來說完全是愚蠢的 - 甚至在經過足夠的時間之後,對自己來說也是如此。

這裏有經驗的我個人的規則,建立一個功能時,有許多條件檢查:

  1. 組條件爲邏輯單元,在可能的情況
  2. 使用明確命名爲中間值,以簡化的可讀性和調試。
  3. 避免重複重複相同的邏輯構造(見上文)。
  4. 如果可能,請將複雜或昂貴的條件重構爲單獨的函數。
  5. 如果可能,請使用方法頂部的提前退出條件退出,但是...
  6. 避免在整個方法體內使用返回語句。
  7. 不要依賴運算符優先級,使用括號來組合語句。
  8. 避免依賴縮進,即使只有一個語句也要使用塊({...}),這有助於維護性。
相關問題