2010-06-28 91 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对象或类似的东西。