Enumeration of ingenious alternatives to if - else

Posted by popcop on Mon, 17 Jan 2022 06:32:32 +0100

Scenario: when some data needs to be received and processed in our project, because they come from different channels (such as Alibaba and Tencent), different channels need different processing methods. Let's write a common Demo to realize the scenario.

1. First, build an abstract class of basic rules, GeneralChannelRule, and define an abstract method {process(), which needs to be implemented by different channels.

public abstract class GeneralChannelRule {

    public abstract void process();

}

2. Create a simple enumeration class.

public enum ChannelRuleEnum {

    ALIBABA("Alibaba"),
    TENCENT("Tencent");

    private String code;

    ChannelRuleEnum(String channel) {
        this.code = channel;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }
}

3. Define an Alibaba rule class to handle the specific processing logic of Alibaba channel data.

public class AlibabaChannelRule extends GeneralChannelRule {

    @Override
    public void process() {
        // Alibaba data processing logic
        System.out.println("This is Alibaba");
    }
}

4. Define a Tencent rule class to handle the specific processing logic of Tencent channel data.

public class TencentChannelRule extends GeneralChannelRule {

    @Override
    public void process() {
        // Tencent data processing logic
        System.out.println("This is Tencent");
    }
}

5. Use rules to process data.

public class Demo {

    public static void main(String[] args) {
        // The data received by the simulation is from Alibaba
        String channel = "Alibaba";
        GeneralChannelRule rule = null;
        if (ChannelRuleEnum.ALIBABA.getCode().equals(channel)) {
            rule = new AlibabaChannelRule();
        } else if (ChannelRuleEnum.TENCENT.getCode().equals(channel)) {
            rule = new TencentChannelRule();
        } else {
            // No matches
        }
        // Execution logic
        rule.process();
    }
}

6. The figure shows the implementation results.

Through the above method, the requirements can be realized.

However, there are two disadvantages:

First, when we need to add new channels, we need to modify and adjust the logic in the main method. This violates the open and closed rules in design patterns. The core idea of open and closed rules is that software entities are extensible and cannot be modified. In other words, it is open to extensions and closed to modifications.

Second, after adding new channels, modifying the code will produce a lot of if - else, which is not very elegant.

In order to solve the above two problems, we can optimize with the help of enumeration classes.

1. Adjust the enumeration class, add an attribute GeneralChannelRule, build the corresponding implementation class GeneralChannelRule for the corresponding channel, and add a matching method match().  

public enum ChannelRuleEnum {

    ALIBABA("Alibaba", new AlibabaChannelRule()),

    TENCENT("Tencent", new TencentChannelRule());

    private String code;

    private GeneralChannelRule channelRule;

    /**
     * matching
     * @param code Channel value
     * @return
     */
    public static ChannelRuleEnum match(String code){
        ChannelRuleEnum[] values = ChannelRuleEnum.values();
        for (ChannelRuleEnum value : values) {
            if(value.code.equals(code)){
                return value;
            }
        }
        return null;
    }

    ChannelRuleEnum(String channel, GeneralChannelRule channelRule) {
        this.code = channel;
        this.channelRule = channelRule;
    }

    public GeneralChannelRule getChannelRule() {
        return channelRule;
    }

    public void setChannel(GeneralChannelRule channelRule) {
        this.channelRule = channelRule;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }
}

2. Rewrite the program.

public class Demo {

    public static void main(String[] args) {
        // The data received by the simulation is from Tencent
        String channel = "Tencent";
        ChannelRuleEnum channelRule = ChannelRuleEnum.match(channel);
        GeneralChannelRule rule = channelRule.getChannelRule();
        rule.process();
    }
}

3. The results are as follows.

By using the enumeration class, bind the key to the specific implementation of the channel rule in the enumeration. Through optimization, you can reduce if - else and make the code more elegant. At the same time, if you need to add new channels, you need to do two steps to complete it. In this way, there is no need to change the original code logic, which is in line with the open and closed principle. The operation steps are as follows:

  1. Define the new channel implementation class, inherit the general channelrule abstract class, and implement its abstract method process().
  2. Add the corresponding channel implementation class in the enumeration class ChannelRuleEnum.

The above is a clever alternative to if - else by enumerating classes. There are many excellent solutions to replace if - else (such as policy mode, factory mode, etc.), and interested friends can consult relevant materials.

Topics: Java Design Pattern