How to avoid using if else in large quantities in Java project?

  • 2021-10-11 18:10:30
  • OfStack

Avoid using if-else in large quantities

Beginners may overlook one point. In fact, if-else is a process-oriented implementation.

So, how do you avoid using if-else heavily in object-oriented programming?

There are many solutions on the network, including factory mode, policy mode and even rule engine (this is too heavy)......

All these have a common shortcoming, and they are still too heavy to use. Although it avoids too many if-else, it will add a lot of extra classes, which I always think is very impractical and can only be used as a certain pattern of learning.

It can replace a large number of if-else statements, and has good readability and extensibility, and can appear lightweight at the same time. I recommend using policy enumeration to eliminate if-else.

How to use it, let's start with a business case-

If there is such a requirement that you need to realize the memo function of knowing what to do within 7 days in 1 week, it will involve a process judgment, and you may immediately think of using if-else, then it may be realized like this-


//if-else Formal judgment 
  public String getToDo(String day){
      if("Monday".equals(day)){
          ...... Omit complex statements 
         return " English class today ";
     }else if("Tuesday".equals(day)){
          ..... Omit complex statements 
          return " I have a Chinese class today ";
     }else if("Wednesday".equals(day)){
         ...... Omit complex statements 
         return " Math class today ";
      }else if("Thursday".equals(day)){
         ...... Omit complex statements 
        return " Music class today ";
    }else if("sunday".equals(day)){
         ...... Omit complex statements 
        return " Programming class today ";
     }else{
          Omitted here 10086 Row ......
     }
 }

This kind of code, in business logic, a small amount is good. If there are hundreds of judgments, the whole business logic may be full of if-else, which is neither elegant nor redundant.

At this point, you can consider replacing the heap of process-oriented if-else implementations with a policy enumeration.

First, define an getToDo () call method, if "Monday" is passed in, that is, the parameter "Monday".


// Policy enumeration judgment 
public String getToDo(String day){
    CheckDay checkDay=new CheckDay();
    return checkDay.day(DayEnum.valueOf(day));
}

In the getToDo () method, one DayEnum enumeration element is obtained through DayEnum. valueOf ("Monday"), where Monday is obtained.

Next, execute checkDay. day (DayEnum. valueOf ("Monday")) and you get into the day () method, where a policy match is made with dayEnum. toDo (). Note that DayEnum. valueOf ("Monday") gets Monday in the enumeration, so Monday. toDo () is executed, that is, toDo () in Monday is executed--


public class CheckDay {
    public String day( DayEnum dayEnum) {
        return dayEnum.toDo();
    }
}

Why is the above execution process like this? Only when I entered the DayEnum enumeration did I know what was going on-(Voice-over: When I first touched the strategy mode, I was suddenly surprised. It turned out that the enumeration could still be played like this)


public enum DayEnum {
    Monday {
        @Override
        public String toDo() {
            ...... Omit complex statements 
            return " English class today ";
        }
    },
    Tuesday {
        @Override
        public String toDo() {
            ...... Omit complex statements 
            return " I have a Chinese class today ";
        }
    },
    Wednesday {
        @Override
        public String toDo() {
            ...... Omit complex statements 
            return " Math class today ";
        }
    },
    Thursday {
        @Override
        public String toDo() {
            ...... Omit complex statements 
            return " Music class today ";
        }
    };
    public abstract String toDo();
}

In the DayEnum enumeration attribute, a method that implements the toDo () abstraction is defined


public abstract String toDo();

In each enumeration element, the toDo () abstract method is overridden. In this way, when passing the reference DayEnum. valueOf ("Monday") to dayEnum. toDo (), it essentially goes to the DayEnum enumeration to find the enumeration element corresponding to the Monday definition, and then executes its internally overridden toDo () method. In the form of if-esle, it is similar to "Monday". When equals (day) is matched to true, its interior can be obtained.

To sum up 1, the policy enumeration is to use the policy mode in the enumeration. The so-called policy mode is to give you a key, which can be immediately guided to find the door that can be opened in a certain agreed way. For example, the key I gave you is called "Monday". Then, you can immediately find the Monday door in the enumeration through the agreed way dayEnum. toDo (), and then enter the door to do what you want to do toDo (), in which the rooms behind each door have different functions, but they all have the same abstract function-toDo (), that is, the common place of each room can be used to do something, but what can be done is different. In this case, toDo () in each gate can get different string returns according to different strategy modes, for example, "English class today", "Chinese class today", and so on.

It can be seen that extracting process judgments into policy enumeration can also decouple a pile of judgments, thus avoiding presenting a large number of redundant if-else in business code logic.

Here, there is one case, that is, if there is a judgment that multiple repetitions share the same function, for example, in if-else, this is the case


public String getToDoByIfElse(String day){
    if("Monday".equals(day)||"Tuesday".equals(day)||"Wednesday".equals(day)){
        ...... Omit complex statements 
        return " English class today ";
    }else if("Thursday".equals(day)){
        ......
    }
}

So, how should we use it under policy enumeration to avoid code redundancy?

You can refer to the following ideas under 1, set up an internal policy enumeration, and point external references with the same function to the same internal enumeration element, so that the call repetition function can be realized-


public enum DayEnum {
    // That points to the internal enumeration 1 You can perform the same repetitive function by using one attribute 
    Monday(" Week 1", Type.ENGLISH),
    Tuesday(" Week 2", Type.ENGLISH),
    Wednesday(" Week 3", Type.ENGLISH),
    
    Thursday(" Week 4", Type.CHINESE);
    private final Type type;
    private final String day;
    DayEnum(String day, Type type) {
        this.day = day;
        this.type = type;
    }
    String toDo() {
        return type.toDo();
    }
    /**
     *  Internal policy enumeration 
     */
    private enum Type {
        ENGLISH {
            @Override
            public String toDo() {
                ...... Omit complex statements 
                return " English class today ";
            }
        },
        CHINESE {
            @Override
            public String toDo() {
                ...... Omit complex statements 
                return " I have a Chinese class today ";
            }
        };
        public abstract String toDo();
    }
}

If you want to extend its judgment process, you only need to add one attribute and internal toDo (implementation) directly in the enumeration, and you can add a new judgment process, while external, you can still use the same entry dayEnum. toDo ().

Perhaps, there will be such a question: Why do you define an abstract method in an enumeration and implement it in each enumeration element?

This function is similar to the way that a subclass inherits a parent class. DayEnum is similar to a parent class, and the elements in the DayEnum enumeration are quite subclasses. When the abstract method toDo () is defined in the parent class, its inherited subclass will implement the toDo () method by default, so that the enumeration can be written as follows:


private enum Type {
        ENGLISH {
            @Override
            public String toDo() {
                return " English class today ";
            }
        } ; 
        public abstract String toDo();
    }

I like to use policy enumeration to eliminate substitution in a large number of if-else. In a word, using policy enumeration can handle all kinds of complex judgments flexibly, and has good readability and extensibility. It is more like functional programming, that is, passing in one parameter can get the value returned in the corresponding mode.

If if-else is used in large quantities in the business logic of Java, it is process-oriented, because if-else in the business logic is judged from top to bottom by one if followed by one if. If you make a breakpoint on each if and go down debug, you will know that it is actually process-oriented.

Therefore, if there are a large number of if-else in the project, it is really a thing that affects the performance. Although this performance is negligible, isn't it better to have a better replacement?


Related articles: