是否有超级缩进代码的替代方案?

时间:2008-12-11 16:52:22

标签: language-agnostic coding-style indentation

我经常遇到必须执行大量检查的代码,并且在真正做任何事情之前最终会缩进至少五到六个级别。我想知道有哪些替代方案。

下面我发布了一个我正在谈论的例子(这不是实际的生产代码,只是我想到的东西)。

public String myFunc(SomeClass input)
{
    Object output = null;

    if(input != null)
    {
        SomeClass2 obj2 = input.getSomeClass2();
        if(obj2 != null)
        {
            SomeClass3 obj3 = obj2.getSomeClass3();
            if(obj3 != null && !BAD_OBJECT.equals(obj3.getSomeProperty()))
            {
                SomeClass4 = obj3.getSomeClass4();
                if(obj4 != null)
                {
                    int myVal = obj4.getSomeValue();
                    if(BAD_VALUE != myVal)
                    {
                        String message = this.getMessage(myVal);
                        if(MIN_VALUE <= message.length() &&
                           message.length() <= MAX_VALUE)
                        {
                            //now actually do stuff!
                            message = result_of_stuff_actually_done;
                        }
                    }
                }
            }
        }
    }
    return output;
}

7 个答案:

答案 0 :(得分:16)

请参阅Flattening Arrow Code寻求帮助。

  
      
  1. 用防护装置替换条件   条款。
  2.   
  3. 将条件块分解为   单独的功能。
  4.   
  5. 将否定支票转换为   积极的检查。
  6.   

答案 1 :(得分:8)

早退:

if (input == null) {
    return output;
}

答案 2 :(得分:7)

是的,有另一种选择。

请永远不要那样编码(除非你维护自己的代码)

我必须维护这样的代码,并且像Charles_Bronsonn电影一样糟糕(有些人喜欢那些电影)

这种代码通常来自程序语言,例如C(C程序:P)无论如何。

这就是ObjectOrientedProgrammng成为主流的原因。它允许您创建对象并向其添加状态。使用该状态创建操作。他们不仅是财产持有人。

我知道你构成了那个场景,但大多数时候所有这些条件都是业务规则!! 。大多数情况下,这些规则会更改,如果原始开发人员不再在那里(或者已经过了几个月),那么修改该代码将没有可行的方法。这些规则难以阅读。而且很多痛苦来自于此。

你能做什么?

1。)使用私有成员变量(AKA属性,属性,实例变量等)保持对象的状态INSIDE对象

2。)将方法设为私有(这是访问级别的用途),这样任何人都不能错误地调用它们并将程序放在NullPointerException域中。

3。)创建定义条件的方法。这就是他们所谓的自我记录代码

所以而不是

// validates the user has amount
if( amount > other && that != var || startsAligned() != false  ) {
}

创建方法

if( isValidAmount() ) {
}

private boolean isValidAmount() {
   return ( amount > other && that != var || startsAligned() != false  );
}

我知道它看起来很冗长,但允许人类能够阅读代码。编译器不关心可读性。

那么你用这种方法看起来会怎么样呢?

喜欢这个。

// these are business rules
// then it should be clear that those rules are
// and what they do.

// internal state of the object.
private SomeClass2 obj2;
private SomeClass3 obj3;
private SomeClass4 obj4;

//public String myFunc( SomeClass input ) {
public String myComplicatedValidation( SomeClass input ) {
    this.input = input;
    if ( isValidInput() && 
        isRuleTwoReady() &&
        isRuleTreeDifferentOf( BAD_OBJECT ) &&
        isRuleFourDifferentOf( BAD_VALUE ) && 
        isMessageLengthInRenge( MIN_VALUE , MAX_VALUE ) ) { 
                message = resultOfStuffActuallyDone();
    }
}

// These method names are self explaining what they do.
private final boolean  isValidInput() {
    return  this.input != null;
}
private final boolean isRuleTwoReady() {
    obj2 = input.getSomeClass2();
    return obj2 != null ;
}
private final boolean isRuleTreeDifferentOf( Object badObject ) {
    obj3 = obj2.getSomeClass3();
    return obj3 != null && !badObject.equals( obj3.getSomeProperty() );
}
private final boolean isRuleFourDifferentOf( int badValue ) {
    obj4 = obj3.getSomeClass4();
    return obj4 != null && obj4.getSomeValue() != badValue;
}
private final boolean isMessageLengthInRenge( int min, int max ) {
    String message = getMessage( obj4.getSomeValue() );
    int length = message.length();
    return length >= min && length <= max;
}

我知道,它看起来更像编码。但想想这个。规则几乎是人类可读的

    if ( isValidInput() && 
        isRuleTwoReady() &&
        isRuleTreeDifferentOf( BAD_OBJECT ) &&
        isRuleFourDifferentOf( BAD_VALUE ) && 
        isMessageLengthInRenge( MIN_VALUE , MAX_VALUE ) ) { 
                message = resultOfStuffActuallyDone();
    }

几乎可以读作

if is valid input 
and rule two is ready 
and rule three is not BAD OBJECT 
and rule four is no BAD_VALUE 
and the message length is in range

通过保持规则变小,编码员可以很容易地理解它们而不是害怕刹车。

可以在 http://www.refactoring.com/

了解更多内容

答案 3 :(得分:2)

是的,您可以按如下方式删除缩进:

基本上按顺序进行检查,并与失败而不是成功进行比较。 它删除了嵌套并使其更容易跟踪(IMO)。

public String myFunc(SomeClass input)
{
    Object output = null;

    if (input == null)
    {
        return null;
    }

    SomeClass2 obj2 = input.getSomeClass2();
    if (obj2 == null)
    { 
        return null;
    }

    SomeClass3 obj3 = obj2.getSomeClass3();
    if (obj3 == null || BAD_OBJECT.equals(obj3.getSomeProperty()))
    {
        return null;
    }

    SomeClass4 = obj3.getSomeClass4();
    if (obj4 == null)
    {
        return null;
    }
    int myVal = obj4.getSomeValue();
    if (BAD_VALUE == myVal)
    {
        return null;
    }
    String message = this.getMessage(myVal);
    if (MIN_VALUE <= message.length() &&
       message.length() <= MAX_VALUE)
    {
        //now actually do stuff!
        message = result_of_stuff_actually_done;
    }
    return output;
}

答案 4 :(得分:1)

你可以使用guard子句来摆脱一些嵌套。

public String myFunc(SomeClass input)
{
    Object output = null;

    if(input == null) return "";

    SomeClass2 obj2 = input.getSomeClass2();
    if(obj2 == null) return "";

    SomeClass3 obj3 = obj2.getSomeClass3();
    if(obj3 == null || BAD_OBJECT.equals(obj3.getSomeProperty()))
    {
        return "";
    }

    SomeClass4 = obj3.getSomeClass4();
    if(obj4 == null) return "";

    int myVal = obj4.getSomeValue();
    if(BAD_VALUE == myVal) return "";

    String message = this.getMessage(myVal);
    if(MIN_VALUE <= message.length() &&
           message.length() <= MAX_VALUE)
    {
         //now actually do stuff!
         message = result_of_stuff_actually_done;
    }

    return output;
}

更改我用来说明指向抛出描述性异常的语句的所有return "";语句。

答案 5 :(得分:1)

如果您不需要处理停止,请不要嵌入。

例如,你可以这样做:

if(input == null && input.getSomeClass2() == null && ...)
    return null;

// Do what you want.

假设您正在使用Java之类的语言来命令条件语。

或者你可以:

if(input == null && input.getSomeClass2() == null)
    return null;

SomeClass2 obj2 = input.getSomeClass2();
if(obj2 == null)
    return null;

...

// Do what you want.

对于更复杂的案例。

如果您不需要处理,我们的想法是从方法返回。嵌入大型嵌套if几乎不可能阅读。

答案 6 :(得分:0)

如果它只是一个可读性问题,你可以通过将嵌套移动到另一个方法来使其更清晰。如果您愿意,还可以转换为警卫风格。

public String myFunc(SomeClass input)
{
    Object output = null;

    if (inputIsValid(input))
    {
      //now actually do stuff!
      message = result_of_stuff_actually_done;
    } 

    return output;
}


private bool inputIsValid(SomeClass input)
{

    // *****************************************
    // convert these to guard style if you like   
    // ***************************************** 
    if(input != null)
    {
        SomeClass2 obj2 = input.getSomeClass2();
        if(obj2 != null)
        {
            SomeClass3 obj3 = obj2.getSomeClass3();
            if(obj3 != null && !BAD_OBJECT.equals(obj3.getSomeProperty()))
            {
                SomeClass4 = obj3.getSomeClass4();
                if(obj4 != null)
                {
                    int myVal = obj4.getSomeValue();
                    if(BAD_VALUE != myVal)
                    {
                        String message = this.getMessage(myVal);
                        if(MIN_VALUE <= message.length() &&
                           message.length() <= MAX_VALUE)
                        {
                            return true;
                        }
                    }
                }
            }
        }
    }
    return false;
}