我有一种遵循以下模式的方法:

void myMethod(String arg1) {
  SomeObject foo = getSomeObject(arg1);

  if(foo != null) {
    SomeOtherObject bar = foo.getSomeOtherObject();

    if(bar != null) {
      bar.doSomething();

      if(bar.isGood()) {
        YetAnother baz = getAnotherByName(bar.getAnotherName());

        if(baz != null) {
          if(baz.exitEarly()) {
            foo.recordEarlyExit(baz.getName());
            return;
          }
        }
      }
    }
  }
  doNormalThing();
}


我想知道是否有一种更干净的方法来获得相同的行为而没有那么多层次。

如果最后不必做doNormalThing();,我可以做这样的事情:

void myMethod(String arg1) {
  SomeObject foo = getSomeObject(arg1);
  if(foo == null) { return; }

  SomeOtherObject bar = foo.getSomeOtherObject();
  if(bar == null) { return; }

  bar.doSomething();
  if(!bar.isGood()) { return; }

  YetAnother baz = getAnotherByName(bar.getAnotherName());

  if(baz == null) { return; }

  if(baz.exitEarly()) {
    foo.recordEarlyExit(baz.getName());
  }
}


我基本上是在做上面的事情,但是在所有doNormalThing();之前添加return。但这是很多重复,如果我需要更改某些内容,则必须在所有这些步骤中进行。

我可以做类似将其包装在try{ ... } catch (DoNormalThingException e) { doNormalThing(); }中的操作,并且仅当我想在从该方法返回之前调用该方法时才抛出DoNormalThingException,而当baz.exitEarly()为true时不抛出它。但这似乎也不干净,而且似乎在滥用异常。

如果只是在所有条件中检查null,那么我可以将其包装在try中,并且仅在抛出doNormalThing()时才运行NullPointerException。这比其他基于异常的方法要干净得多:我不需要任何条件,而且我捕获的是合法异常,而不是仅用于控制流的组合异常。但是,并非所有检查都针对== null,我也不想掩盖来自更深层方法调用的NPE。

如果只有Java有goto ...

编辑:所以我知道这种重构有一个名字,那就是:用Guard子句替换嵌套条件。这是我试图做的,但是如果您有在大多数情况下但不是全部都需要调用的额外方法,那么它就不能很好地工作。不过,我认为我会提到它以帮助其他人找到这个问题。

最佳答案

一种选择是将除doNormalThing方法调用之外的所有调用包装在另一种方法中,该方法返回随后是否执行doNormalThing

void myMethod(String arg1) {
    if (myMethodInternal(arg1)) {
        doNormalThing();
    }
}

private boolean myMethodInternal(String arg1) {
    SomeObject foo = getSomeObject(arg1);
    if (foo == null) {
        return true;
    }

    SomeOtherObject bar = goo.getSomeOtherObject();
    if (bar == null) {
        return true;
    }
    // etc

    if (baz.exitEarly()) {
        foo.recordEarlyExit(baz.getName());
        return false;
    }
    return true;
}


感觉不是很干净,但是至少可以工作。您也可以毫无例外地使用try/finally-使用boolean字段来确定是否执行doNormalThing

10-06 05:38