执行Extract Method时返回语句

时间:2010-06-28 17:31:33

标签: c++ refactoring

假设您有一个很长的方法,如下所示:

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;
}

我正在努力捣乱代码。我想将龙屠杀部分提取到

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()替换monster()中的代码。

但是有一个问题。该部分的中间有一个返回声明。如果我保留处理handleDragon()返回码的部分,它将把垃圾保留在大方法中。

除了使用异常之外,还有一种优雅而安全的方法可以从怪物方法中重构这段代码吗?如何处理这些类型的情况?

4 个答案:

答案 0 :(得分:2)

如果龙杀手可用,则从handleDragon方法返回0:

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方法,以解释返回的值。

答案 1 :(得分: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)。
  • 一个函数某事,无论它做什么,都应该在它的名字中可见。因此,函数名称中应该有 动词 handle dragon() {{1} } call)。 TheKing()不是动词,不是你可以做的事情。如果我看到标识符monsters,我认为它是怪物的容器。
  • 检查monsters只是无用的噪音,因为if(x == true)更简洁,更简单,也是如此。

答案 2 :(得分: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 :(得分:0)

问题是关于策略所以我认为Richard Fearn的答案很好。

要使其成为重构模式,它看起来像:

上下文:提取更大方法中间的部分。

问题:该部分包含return语句。

<强>解决方案

  1. 将代码解压缩到一个新方法,返回与更大方法相同的类型。
  2. 找到那种没有任何意义的类型的值。称该值为CONTINUE。
  3. 在返回CONTINUE的新方法的末尾添加一条语句。
  4. 在较大的方法中测试来自CONTINUE的新方法的返回值。如果不是那么返回该值。
  5. 这将是主要方法。下一步,你可以将新方法的返回值重构为更有意义的东西(比如sbi的答案)。而且你必须找到一种方法来处理返回类型不是标量或简单类型的情况,返回NULL对象或其他类型。