代码样式:多次返回

时间:2011-11-28 10:51:52

标签: java return design-patterns

我正在写这样的方法:

if (hasFoo()) {
   return calculateFoo();
} else if (hasBar()) {
   return calculateBar();
} else {
   return calculateBaz();
}

getter相当昂贵,has...()检查会复制很多逻辑,或者只是重用getter。我可以让has...()方法将get...()的结果存储在一个字段中并使getter变得懒惰,但has...()没有任何副作用会很好。我可以使用嵌套的try {} catch {}块来编写它,但这看起来并不优雅。似乎应该有更好的解决方案...

编辑:将get...()更改为calculate...(),以明确说明它们很贵。

8 个答案:

答案 0 :(得分:4)

int result = 0;

if (hasFoo()) {
   result = getFoo();
} else if (hasBar()) {
   result = getBar();
} else {
   result = getBaz();
}

return result;

是我喜欢使用的习惯用法 - 在调试时更容易检查变量值。

答案 1 :(得分:2)

我认为

没有错
Object fooBarBaz = null;

if (hasFoo()) {
   foo = getFoo();
} else if (hasBar()) {
   fooBarBaz = getBar();
} else {
   fooBarBaz = getBaz();
}

return fooBarBaz;

答案 2 :(得分:0)

编辑:如果我正确地解释你的评论,听起来你实际想要的东西如下:

Result result = calculateFoo();
if (result != null) {
    return result;
}
result = calculateBar();
if (result != null) {
    return result;
}
return calculateBaz();

...如果相应的calculate方法返回false,则每个null方法返回has。现在,如果null是一个有效的“真实”返回值,您可以始终包装结果,以便calculateFoo返回一个值,该值基本上可以说,“是的,我有一个有效值,它是X “或”不,我没有有效的值“(”可能“类型)。


原始回答

我会保持你的代码完全一样。当这是最明确的方法时,我发现有多个return语句没有问题 - 在这种情况下我相信它是。

你明确表示,一旦你到达了每一个“叶子”部分,就会确切地知道返回值是什么,并且在离开方法之前应该执行的唯一其他代码是任何清理finally块中的代码。

有一个单一的出口点在没有try / finally或GC的语言中是有意义的(你真的想确保你在一个地方做所有的清理工作)但是在Java中,我认为当你知道时返回结果表明您的意图比使用单独的局部变量更明确。

话虽如此,考虑的另一种选择是使用条件运算符,布局你的代码,因此它显然会经历一系列测试并在找到第一个“匹配”后立即返回:

return hasFoo() ? getFoo()
     : hasBar() ? getBar()
     : getBaz();

缺点是这种模式在您第一次看到它时看起来有点奇怪 - 但是一旦您习惯了它,我发现它是一种非常巧妙的编码这种逻辑的方式。

答案 3 :(得分:0)

我更喜欢这样:

if (hasFoo()) {
    return calculateFoo();
}

if (hasBar()) {
    return calculateBar();
}

return calculateBaz();

所有的品味和惯例。

答案 4 :(得分:0)

我不确定这是不是你的情况,但我会尝试完全重构代码。目前,据我所知,您的代码看起来像这样(示例):

boolean hasFoo() {
    DataObject do = getSomeDataSource().getSomeDataObject();
    if (do.getF() != null && do.getO() != null) {
        return true;
    } else {
        return false;
    }
}

Foo getFoo() {
    DataObject do = getSomeDataSource().getSomeDataObject();
    Foo result = new Foo(do.getF(), do.getO());
    return result;
}

基本上这里发生的是使用相同的代码来检查是否可以返回Foo并且也构造Foo本身。我会重构它:

/**
* @returns instance of Foo or null if Foo is not found
*/
Foo getFoo() {
    DataObject do = getSomeDataSource().getSomeDataObject();
    F f = do.getF();
    if (f == null) {
        return null; //Foo can not be created
    }
    O o = do.getO();
    if (o == null) {
        return null; //Foo can not be created
    }

    return new Foo(f,o);
}

现在您的原始代码将与此类似:

Result r;

r = getFoo();
if (r == null) {
    r = getBoo();
}
if (r == null) {
    r = getDoo();
}
return r;

答案 5 :(得分:0)

这不是“可以做多次退货”问题 - 您的多次退货都没问题。

这是重构和/或状态存储问题。

如果你有:

bool hasXXX() {
    // do lots of stuff
    ...

    return has_xxx;
}

double calculateXXX() {
    // do the same lots of stuff
    ...

    // do some more stuff
    ...

    return xxx;
}

然后问题的复杂性取决于hasXXX()计算是否产生了calculateXXX()所需的大量中间值。

您可能需要以下内容:

bool checked_xxx = false;
double xxx_state;

bool hasXXX() {
   // do expensive stuff
   ...

   // save temporary state variables
   xxx_state = ... 

   // remember that we've been here
   checked_xxx = true;

   // send back the required value
   return has_xxx;
}

double calculateXXX() {
    // make sure that hasXXX was called, and is valid
    if (!checked_xxx && !hasXXX()) {
        // should never happen - you called calculateXXX when hasXXX() == false
        throw new RuntimeException("precondition failed");
    }

    // use the previously calculated temporary state variables
    ...

    // send back the final result
    return xxx;
}

答案 6 :(得分:0)

您可以将这些计算分解为单独的对象,而不是hasXXX()calculateXXX(),例如

public interface CalculationModel {
    Object calculate();
}

public class FooCalculationModel implements CalculationModel {
    @Override
    public Object calculate() {
        // Perform Foo calculations
        return result;
    }
}

然后您的if语句可以替换为:

return getCalculationModel().calculate();

当然,你需要某种方法来决定CalculationModel,但这会取代hasFoo(),hasBar()等方法。

答案 7 :(得分:-1)

你可以这样做:

Object bar;
if ((bar = getFoo()) != null) {
  return bar;
} else if ((bar = getBoo()) != null) {
  return bar;
} else {
  return getBaz()
}

这样你只需要调用get方法,但不需要调用

EDIT

这是一种更易读的格式,同样也消除了调用has方法

的需要
Object bar = getFoo()

if (bar == null) {
  bar = getBoo()
}

if (bar == null) {
  bar = getBaz()
}

return bar;