Strategy Enumeration: Eliminate the graceful use of if-else in projects

Text/Zhu Jiqian

I remember when I first came into contact with JAVA object-oriented programming, if I encountered a large number of process judgment statements, almost the whole screen was filled with if-else statements. There were so many that I forgot where the head and where was the tail. However, even if the screen was filled with if-else statements, -else, but I didn’t feel too awkward at the time. After my programming skills gradually improved, when I looked back at the screen-full if-else I had written, there was only one picture in my mind, all of which were Xiang…

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

So, how to avoid using if-else extensively in object-oriented programming?

There are many solution ideas on the Internet, including factory mode, strategy mode, and even rule engines (this is too heavy)…

These all have a common shortcoming, which is that they are still too cumbersome to use. Although it avoids too many if-else, it will add a lot of extra classes. I always feel that it is very impractical and can only be used as a learning mode.

It can replace a large number of if-else statements, has good readability and scalability, and can appear lightweight. 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, it is necessary to realize the memo function of knowing what to do within seven days of the week. This will involve a process judgment. You may immediately think of using if-else. Then, it may be implemented like this–

 //if-else form 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 Chinese class today";
     }else if("Wednesday".equals(day)){
         ...omit complex statements
         return "I have math class today";
     }else if("Thursday".equals(day)){
         ...omit complex statements
         return "Music class today";
     }else if("sunday".equals(day)){
         ...omit complex statements
         return "I have a programming class today";
     }else{
         Line 10086 is omitted here...
   }
}

In business logic, a small amount of this kind of code is okay, but if there are hundreds of judgments, the entire business logic may be full of if-else, which is neither elegant nor redundant.

At this time, you can consider using the strategy enumeration form to replace this bunch of process-oriented if-else implementations.

First, define a getToDo() calling method. If “Monday” is passed in, that is the parameter “Monday”.

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

In the getToDo() method, a DayEnum enumeration element can be obtained through DayEnum.valueOf(“Monday”), and what is obtained here is Monday.

Next, execute checkDay.day(DayEnum.valueOf(“Monday”)) and you will enter the day() method. Here, when a policy matching is made through dayEnum.toDo() . Note that DayEnum.valueOf(“Monday”) gets Monday in the enumeration. In this way, Monday.toDo() is actually executed, that is to say, toDo() in Monday will be executed–

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

Why is the above execution process like this? Only when you enter the DayEnum enumeration do you know what’s going on – (Voiceover: When I first came into contact with the strategy mode, I was shocked to find that enumeration can 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 Chinese class today";
        }
    },
    Wednesday {
        @Override
        public String toDo() {
            ...omit complex statements
            return "I have math class today";
        }
    },
    Thursday {
        @Override
        public String toDo() {
            ...omit complex statements
            return "Music class today";
        }
    };
    public abstract String toDo();
}

Among the DayEnum enumeration properties, an abstract method that implements toDo() is defined–

 public abstract String toDo();

In each enumeration element, the toDo() abstract method is overridden. In this way, when the parameter DayEnum.valueOf(“Monday”) flows to dayEnum.toDo(), it essentially finds the enumeration element corresponding to Monday’s definition in the DayEnum enumeration, and then executes its internally rewritten toDo( )method. Expressed in the form of if-esle, it is similar to “Monday”.equals(day). When the match is true, you can get its internal content.

To summarize, strategy enumeration is the use of strategy mode in enumeration. The so-called strategy mode means that you are given a key, and according to a certain agreed method, you can be immediately guided to find the door that can be opened. For example, if the key I gave you is called “Monday”, then you can use the agreed method dayEnum.toDo() to immediately find the Monday door in the enumeration, then enter the door and do what you want to do toDo(), Among them, the rooms behind each door have different functions, but they all have the same abstract function-toDo(), that is, the common places in each room are functions that can be used to do something, but what specific things can be done, It’s different. In the case of this article, toDo() in each door can obtain different string returns according to different strategy modes, for example, “I have an English class today”, “I have a Chinese class today”, etc. wait.

It can be seen that extracting process judgments into policy enumerations can also decouple a bunch of judgments to avoid a large number of dense and redundant if-else in the business code logic.

Here, there will be a situation, that is, if there are multiple judgments that repeat the same function, for example, in if-else, it is like this –

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 it be used under strategy enumeration to avoid code redundancy?

You can refer to the following ideas, set up an internal policy enumeration, and point external references with the same function to the same internal enumeration element, so that repeated functions can be called –

public enum DayEnum {
    //Point to the same property of the internal enumeration to perform the same repeated function
    Monday("Monday", Type.ENGLISH),
    Tuesday("Tuesday", Type.ENGLISH),
    Wednesday("Wednesday", Type.ENGLISH),
    
    Thursday("Thursday", 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 Chinese class today";
            }
        };
        public abstract String toDo();
    }
}

If you want to expand its judgment process, you only need to directly add an attribute and internal toDo (implementation) to the enumeration to add a new judgment process. Externally, you can still use the same entry dayEnum.toDo().

Perhaps, there will be such a question: Why is an abstract method defined in an enumeration implemented in each enumeration element?

This function is similar to how a subclass inherits a parent class. DayEnum is similar to a parent class, and the elements in the DayEnum enumeration are equivalent to its subclasses. When the abstract method toDo() is defined in the parent class, the inherited subclass will implement the toDo() method by default. In this way, the enumeration can be written like this:

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

I like to use strategy enumerations to eliminate substitutions in bulk if-else. In short, using strategy enumerations can flexibly handle various complex judgments, and has better readability and scalability. , it is more like functional programming, that is, passing in a parameter, you can get the value returned in the corresponding mode.

If if-else is used in large quantities in business logic in Java, it is process-oriented, because if-else in business logic is judged from top to bottom, one if after another, and put a mark on each if. Breakpoint and debug, you will understand that it is actually process-oriented.

It can be seen that if there are a lot of if-else in the project, it will really affect the performance. Although this performance is negligible, wouldn’t it be better to have a better alternative?

The knowledge points of the article match the official knowledge files, and you can further learn relevant knowledge. Java skill treeControl execution processif-else139364 people are learning the system