How do you handle huge if-conditions?

后端 未结 21 1728
一向
一向 2021-01-31 17:14

It\'s something that\'s bugged me in every language I\'ve used, I have an if statement but the conditional part has so many checks that I have to split it over multiple lines, u

相关标签:
21条回答
  • 2021-01-31 17:49

    I like to break them down by level, so I'd format you example like this:

    if (var1 = true
     && var2 = true
     && var2 = true
     && var3 = true
     && var4 = true
     && var5 = true
     && var6 = true){
    

    It's handy when you have more nesting, like this (obviously the real conditions would be more interesting than "= true" for everything):

    if ((var1 = true && var2 = true)
     && ((var2 = true && var3 = true)
      && (var4 = true && var5 = true))
     && (var6 = true)){
    
    0 讨论(0)
  • 2021-01-31 17:50

    I've seen a lot of people and editors either indenting each condition in your if statement with one tab, or matching it up with the open paren:

    if (var1 == true
        && var2 == true
        && var3 == true
       ) {
        /* do something.. */
    }
    

    I usually put the close paren on the same line as the last condition:

    if (var1 == true
        && var2 == true
        && var3 == true) {
        /* do something.. */
    }
    

    But I don't think this is quite as clean.

    0 讨论(0)
  • 2021-01-31 17:52

    Try looking at Functors and Predicates. The Apache Commons project has a great set of objects to allow you to encapsulate conditional logic into objects. Example of their use is available on O'reilly here. Excerpt of code example:

    import org.apache.commons.collections.ClosureUtils;
    import org.apache.commons.collections.CollectionUtils;
    import org.apache.commons.collections.functors.NOPClosure;
    
    Map predicateMap = new HashMap();
    
    predicateMap.put( isHonorRoll, addToHonorRoll );
    predicateMap.put( isProblem, flagForAttention );
    predicateMap.put( null, ClosureUtils.nopClosure() );
    
    Closure processStudents = 
        ClosureUtils.switchClosure( predicateMap );
    
    CollectionUtils.forAllDo( allStudents, processStudents );
    

    Now the details of all those isHonorRoll predicates and the closures used to evaluate them:

    import org.apache.commons.collections.Closure;
    import org.apache.commons.collections.Predicate;
    
    // Anonymous Predicate that decides if a student 
    // has made the honor roll.
    Predicate isHonorRoll = new Predicate() {
      public boolean evaluate(Object object) {
        Student s = (Student) object;
    
        return( ( s.getGrade().equals( "A" ) ) ||
                ( s.getGrade().equals( "B" ) && 
                  s.getAttendance() == PERFECT ) );
      }
    };
    
    // Anonymous Predicate that decides if a student
    // has a problem.
    Predicate isProblem = new Predicate() {
      public boolean evaluate(Object object) {
        Student s = (Student) object;
    
        return ( ( s.getGrade().equals( "D" ) || 
                   s.getGrade().equals( "F" ) ) ||
                 s.getStatus() == SUSPENDED );
      }
    };
    
    // Anonymous Closure that adds a student to the 
    // honor roll
    Closure addToHonorRoll = new Closure() {
      public void execute(Object object) {
        Student s = (Student) object;
    
        // Add an award to student record
        s.addAward( "honor roll", 2005 );
        Database.saveStudent( s );
      }
    };
    
    // Anonymous Closure flags a student for attention
    Closure flagForAttention = new Closure() {
      public void execute(Object object) {
        Student s = (Student) object;
    
        // Flag student for special attention
        s.addNote( "talk to student", 2005 );
        s.addNote( "meeting with parents", 2005 );
        Database.saveStudent( s );
      }
    };
    
    0 讨论(0)
  • 2021-01-31 17:52

    If you happen to be programming in Python, it's a cinch with the built-in all() function applied over the list of your variables (I'll just use Boolean literals here):

    >>> L = [True, True, True, False, True]
    >>> all(L) # True, only if all elements of L are True.
    False
    >>> any(L) # True, if any elements of L are True.
    True
    

    Is there any corresponding function in your language (C#? Java?). If so, that's likely the cleanest approach.

    0 讨论(0)
  • 2021-01-31 17:54

    I'll often split these up into component boolean variables:

    bool orderValid = orderDate < DateTime.Now && orderStatus != Status.Canceled;
    bool custValid = customerBalance == 0 && customerName != "Mike";
    if (orderValid && custValid)
    {
    ...
    
    0 讨论(0)
  • 2021-01-31 17:55

    Check out Implementation Patterns by Kent Beck. There is a particular pattern I am thinking of that may help in this situation... it is called "Guards". Rather than having tons of conditions, you can break them out into a guard, which makes it clear which are the adverse conditions in a method.

    So for example, if you have a method that does something, but there are certain conditions where it shouldn't do something, rather than:

    public void doSomething() {
        if (condition1 && condition2 && condition3 && condition4) {
            // do something
        }
    }
    

    You could change it to:

    public void doSomething() {
        if (!condition1) {
            return;
        }
    
        if (!condition2) {
            return;
        }
    
        if (!condition3) {
            return;
        }
    
        if (!condition4) {
            return;
        }
    
        // do something
    }
    

    It's a bit more verbose, but a lot more readable, especially when you start having weird nesting, the guard can help (combined with extracting methods).

    I HIGHLY recommend that book by the way.

    0 讨论(0)
提交回复
热议问题