2010-06-28 40 views
2

比方說,你有一個很長的方法,像這樣:return語句做提取方法

int monster() 
{ 
    int rc = 0; 

    // some statements ... 

    if (dragonSlayer.on_vacation()) { 
     cout << "We are screwed!\n"; 
     if (callTheKing() == true) 
      return 1; 
     else 
      return 2; 
    } else { 
     cout << "We are saved!\n"; 
     slayTheDragon(); 
    } 

    // rest of long method... 

    return rc; 
} 

和我工作skeletonizing的代碼。我想提取龍殺死部分到

int handleDragon() { 
    if (dragonSlayer.on_vacation()) { 
     cout << "We are screwed!\n"; 
     if (callTheKing() == true) 
      return 1; 
     else 
      return 2; 
    } else { 
     cout << "We are saved!\n"; 
     slayTheDragon(); 
    } 

    return 0; // ? 
} 

並用handleDragon()調用替換怪物()中的代碼。

但有一個問題。該部分中間有一個返回聲明。如果我保留處理handleDragon()的返回代碼的部分,它將保持垃圾大方法。

除了使用異常,有沒有一種優雅和安全的方式來重構這段代碼從怪物方法?應如何處理這些類型的情況?

+1

如果你打算比較布爾值與'true'那樣的話,請注意'callTheKing()== true'也是一個布爾值。所以它應該是'(callTheKing()== true)== true'。 – 2010-06-28 18:00:47

+1

更嚴重的是,如果你打算使用返回值而不是例外,那麼你需要一個一致的方案。在這裏你有一個函數返回'int'(成功爲零),其他函數返回'bool'(零失敗)。你只是要求有人混合這兩種方案。 – 2010-06-28 18:02:26

回答

2

返回0從handleDragon方法,如果龍者可用:

int handleDragon() { 
    if (dragonSlayer.on_vacation()) { 
     cout << "We are screwed!\n"; 
     if (callTheKing() == true) 
      return 1; 
     else 
      return 2; 
    } else { 
     cout << "We are saved!\n"; 
     slayTheDragon(); 
     return 0; 
    } 
} 

然後回到monster方法,如果返回值是大於零,返回該值,否則進行:

// some statements ... 

int handleDragonResult = handleDragon(); 
if (handleDragonResult > 0) { 
    return handleDragonResult; 
} 

// rest of long method... 

您還應該記錄handleDragon方法,以解釋返回的值。

0

你不能做到這一點:

int handleDragon() { 
    int rc = 0; 

    if (dragonSlayer.on_vacation()) { 
     cout << "We are screwed!\n"; 
     if (callTheKing() == true) 
      rc = 1; 
     else 
      rc = 2; 
    } else { 
     cout << "We are saved!\n"; 
     slayTheDragon(); 
    } 

    return rc; 
} 

然後:

int monster() 
{ 
    int rc = 0; 

    // some statements ... 

    rc = handleDragon(); 

    // rest of long method... 

    return rc; 
} 

,或者如果你想要做的事與返回代碼:

int monster() 
{ 
    int rc = 0; 

    // some statements ... 

    int handleDragonReturnCode = handleDragon(); 

    if(handleDragonReturnCode == 0) { 
     // do something 
    } 

    else { 
     // do something else 
    } 

    // rest of long method... 

    return rc; 
} 

這是什麼你要?在一般說明中,請避免使用幻數,如12作爲您的返回碼。使用常量,#defineenum

關於return,請嘗試讓一個退出您的功能。正如你發現的那樣,有多個return語句可以使重構變得困難(除非它真的很簡單,否則就理解邏輯)。

+3

_單一入口,單一出口_在純粹的結構化編程和冗長的功能的黑暗時代,殘留在監視器上的幾頁上。堅持它會讓你相信你可以安全地假設一個函數不會過早返回 - 這從來都不是真的,因爲在C++中我們有例外。通過控制流語句,而不是通過操作返回變量,將'if'語句中的實際算法隱藏起來,這些語句都測試返回變量的狀態。 – sbi 2010-06-28 17:55:50

+0

我不會說這是一個「愚蠢的遺留」。我會說這是例外而非規則。我之所以這麼說,是因爲濫用多重回報很容易,而且我看過太多次了。因此,警示說明。我同意你所說的一般,但關於流量控制。 – 2010-06-28 20:01:23

1
enum DragonHandled { DHSuccess, DHKing, DHNoKing }; 

inline DragonHandled askForKing() 
{ 
    if (callTheKing()) 
     return DHKing; 
    else 
     return DHNoKing; 
} 

DragonHandled handleDragon() 
{ 
    if (dragonSlayer.on_vacation()) { 
     cout << "We are screwed!\n"; 
     return askForKing(); 
    } 
    cout << "We are saved!\n"; 
    slayTheDragon(); 
    return DHSuccess; 
} 

int monster() 
{ 
    some_statements(...); 

    DragonHandled handled = handleDragon(); 
    if(handled != DHSuccess) 
     return handled; // enum to int is an implicit cast 

    return more_statements(...); 
} 
  • 除了返回實際簽署數一個功能,我不會再回到int。如果結果有意義,請正確定義該含義(即:enum)。
  • 函數確實是東西,無論它做什麼,都應該在它的名字中可見。所以應該有一個動詞在一個函數的名字(handledragon()callTheKing())。 monsters不是動詞,它不是你可以做的事情。如果我看到一個標識符monsters,我認爲它是一個怪物容器。
  • 檢查if(x == true)只是無用的噪音,因爲if(x)更加簡潔,也是如此。
+0

「怪物」只是我指出這是一個怪物的方法,它不是我的代碼真正的方法。我只是創建了虛構的代碼來陳述我遇到的問題。 – Michael 2010-06-28 18:21:41

+0

在我的方式中,像「怪物」這樣的動詞詞很常見。 – 2010-06-28 22:06:19

+0

@Mike:我是非本地人,所以我可能在這裏錯了。我不會想到你可以把它變成動詞。 Mea culpa ... – sbi 2010-06-28 22:52:34

0

問題是關於戰略,所以我認爲理查德費恩的答案是一個很好的答案。

,使之成爲一個重構模式它看起來是這樣的:

語境:在一個更大的方法的中間段是被提取。

問題:該部分包含返回語句。

  1. 代碼提取到一個新的方法將在返回類型相同更大方法。
  2. 找到一個不代表任何意義的值。調用該值繼續。
  3. 在返回CONTINUE的新方法末尾添加一條語句。
  4. 在較大的方法中,測試CONTINUE的新方法的返回值。如果不是,則返回該值。

這將是主要方法。作爲下一步,您可以將新方法的返回值重構爲更有意義的內容(例如在sbi的答案中)。你必須找到一種方法來處理返回類型不是標量類型或簡單類型的情況,返回一個NULL對象或類似的東西。