原创

优化if-else之Java枚举中的两个小技巧

温馨提示:
本文最后更新于 2020年11月16日,已超过 1,425 天没有更新。若文章内的图片失效(无法正常加载),请留言反馈或直接联系我

还是按常规操作走一波

什么是枚举?

枚举类型是Java 5中新增特性的一部分,它是一种特殊的数据类型,之所以特殊是因为它既是一种类(class)类型却又比类类型多了些特殊的约束,但是这些约束的存在也造就了枚举类型的简洁性、安全性以及便捷性。

大部分人如何使用枚举?

e.g.大部分人都是直接就时一想到枚举,昂,我常量写在枚举中/静态常量。

public enum MenuType {
    CATEGORY,
    PAGE,
    BUTTON
}

1.枚举中的比对值

昂,这个名称我乱起的,哈哈哈,Because match,听到比对我就马上能够想到match,仅此而已,怎么舒服怎么来。

我们只需要传入WindingPolarizationTaskEnum的value,然后使用match方法,就可以返回我们需要的枚举类型了。

public enum WindingPolarizationTaskEnum {

    HIGH_LOW_WITH_GROUND(0, "高压-低压及地"),

    LOW_HIGH_WITH_GROUND(1, "低压-高压及地"),

    HIGH_LOW_GROUND(2, "高压、低压-地"),

    OTHER(3, "其它试验数据");

    WindingPolarizationTaskEnum(Integer number, String desc) {
        this.number = number;
        this.desc = desc;
    }

    private Integer number;

    private String desc;

    /**
     * 根据类型返回具体的WindingPolarizationTaskEnum
     *
     * @param number number
     * @return WindingPolarizationTaskEnum
     */
    public static WindingPolarizationTaskEnum match(Integer number) {
        for (WindingPolarizationTaskEnum item : WindingPolarizationTaskEnum.values()) {
            if (item.number.equals(number)) {
                return item;
            }
        }
        return WindingPolarizationTaskEnum.HIGH_LOW_WITH_GROUND;
    }

    public Integer getNumber() {
        return number;
    }

    public void setNumber(Integer number) {
        this.number = number;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

}

2.其实枚举类型中是可以定义方法的

demo1

来看一下我在学校时期写的一段代码…注释上都有,就不重复解释了。

import com.data.DataService;
import com.model.msgtype.opendevicealarmtype.OpenDeviceAlarm;
import com.model.msgtype.opendeviceonofflinetype.OpenDeviceOnoffline;
import com.model.msgtype.openeventaccessbatchdeliveredtype.OpenEventAccessBatchDelivered;
import com.model.msgtype.openeventaccesstype.OpenEventAccess;
import com.model.msgtype.openeventsuperbrainfacesdeliveredtype.OpenEventSuperBrainFacesDelivered;
import com.model.msgtype.openezvizdetectoralarmtype.OpenEzvizDetectorAlarm;
import com.model.msgtype.openfacecapturetype.OpenFaceCapture;
import com.model.msgtype.openidcardeventtype.OpenIdcardEvent;
import com.model.msgtype.openmessageanpr.OpenMessageAnpr;
import com.model.msgtype.openmessagetma.OpenMessageTma;
import com.model.msgtype.openpassengerflowtype.OpenPassengerFlow;
import com.model.msgtype.openpersonqueuecountingtype.OpenPersonQueueCounting;
import com.response.ErrorCode;
import com.response.hkym.CommonObj;
import com.util.JsonUtil;

import java.io.IOException;

/**
 * 消息类型
 * <p>
 * 我想到的优化(if-else、switch)的解决方案:
 * 1. 使用容器,每个方法都换成一个类,但这样的话,就要多加很多个类
 * 2. 使用反射,但是反射的速度太慢了。
 * 3. 使用函数式接口,使用函数式接口作为容器的元素。
 * 4. 用Runnable。
 * 5. 设计模式(状态模式、策略模式、工厂模式)
 * 6. 枚举 + 方法。
 * </p>
 * @author lzhpo
 */
public enum MsgTypeEnum {

    /** 门禁事件消息 */
    OPEN_EVENT_ACCESS("open_event_access") {
        @Override
        OpenEventAccess run(String content) throws IOException {
            System.out.println("门禁事件消息:" +content);
            return JsonUtil.parse(content, OpenEventAccess.class);
        }
    },
    /** 人证比对事件 */
    OPEN_IDCARD_EVENT("open_idcard_event") {
        @Override
        OpenIdcardEvent run(String content) throws IOException {
            System.out.println("人证比对事件:" +content);
            return JsonUtil.parse(content, OpenIdcardEvent.class);
        }
    },
    /** 客流消息 */
    OPEN_PASSENGERFLOW("open_passengerFlow") {
        @Override
        OpenPassengerFlow run(String content) throws IOException {
            System.out.println("客流消息:" +content);
            OpenPassengerFlow openPassengerFlow = JsonUtil.parse(content, OpenPassengerFlow.class);
            DataService.leave += openPassengerFlow.getLeaveNum();
            DataService.enter += openPassengerFlow.getEnterNum();
            DataService.pass += openPassengerFlow.getLeaveNum() + openPassengerFlow.getEnterNum();
            openPassengerFlow.setEnterNum(DataService.enter);
            openPassengerFlow.setLeaveNum(DataService.leave);
            openPassengerFlow.setPassNum(DataService.pass);
            return openPassengerFlow;
        }
    },
    /** 人脸抓拍消息 */
    OPEN_FACE_CAPTURE("open_face_capture") {
        @Override
        OpenFaceCapture run(String content) throws IOException {
            System.out.println("人脸抓拍消息:" +content);
            return JsonUtil.parse(content, OpenFaceCapture.class);
        }
    },
    /** 门禁批量下发消息 */
    OPEN_EVENT_ACCESS_BATCH_DELIVERED("open_event_access_batch_delivered") {
        @Override
        OpenEventAccessBatchDelivered run(String content) throws IOException {
            System.out.println("门禁批量下发消息:" +content);
            return JsonUtil.parse(content, OpenEventAccessBatchDelivered.class);
        }
    },
    /** 超脑人脸下发消息 */
    OPEN_EVENT_SUPER_BRAIN_FACES_DELIVERED("open_event_super_brain_faces_delivered") {
        @Override
        OpenEventSuperBrainFacesDelivered run(String content) throws IOException {
            System.out.println("超脑人脸下发消息:" +content);
            return JsonUtil.parse(content, OpenEventSuperBrainFacesDelivered.class);
        }
    },
    /** 超脑人脸比对消息 */
    OPEN_EVENT_SUPER_BRAIN_FACES_COMPARISON("open_event_super_brain_faces_comparison") {
        @Override
        OpenEventSuperBrainFacesDelivered run(String content) throws IOException {
            System.out.println("超脑人脸比对消息:" +content);
            return JsonUtil.parse(content, OpenEventSuperBrainFacesDelivered.class);
        }
    },
    /** 萤石探测器报警消息 */
    OPEN_EZVIZ_DETECTOR_ALARM("open_ezviz_detector_alarm") {
        @Override
        OpenEzvizDetectorAlarm run(String content) throws IOException {
            System.out.println("萤石探测器报警消息:" +content);
            return JsonUtil.parse(content, OpenEzvizDetectorAlarm.class);
        }
    },
    /** 设备报警消息 */
    OPEN_DEVICE_ALARM("open_device_alarm") {
        @Override
        OpenDeviceAlarm run(String content) throws IOException {
            System.out.println("设备报警消息:" +content);
            return JsonUtil.parse(content, OpenDeviceAlarm.class);
        }
    },
    /** 设备上下线消息 */
    OPEN_DEVICE_ONOFFLINE("open_device_onoffline") {
        @Override
        OpenDeviceOnoffline run(String content) throws IOException {
            System.out.println("设备上下线消息:" +content);
            return JsonUtil.parse(content, OpenDeviceOnoffline.class);
        }
    },
    /** 车辆抓拍消息 */
    OPEN_MESSAGE_ANPR("open_message_anpr") {
        @Override
        OpenMessageAnpr run(String content) throws IOException {
            System.out.println("车辆抓拍消息:" +content);
            return JsonUtil.parse(content, OpenMessageAnpr.class);
        }
    },
    /** 测温报警消息 */
    OPEN_MESSAGE_TMA("open_message_tma") {
        @Override
        OpenMessageTma run(String content) throws IOException {
            System.out.println("测温报警消息:" +content);
            return JsonUtil.parse(content, OpenMessageTma.class);
        }
    },
    /** 区域人数超限报警消息 */
    OPEN_PERSON_QUEUE_COUNTING("open_person_queue_counting") {
        @Override
        OpenPersonQueueCounting run(String content) throws IOException {
            System.out.println("区域人数超限报警消息:" +content);
            return JsonUtil.parse(content, OpenPersonQueueCounting.class);
        }
    };

    private String type;

    MsgTypeEnum() {
    }

    MsgTypeEnum(String type) {
        this.type = type;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    /** 定义枚举的方法 */
    abstract <T> T run(String content) throws IOException;

    /**
     * 比对消息类型,然后执行run方法,返回对应的content值
     *
     * @param type 消息类型
     * @param content 消息类型对应的内容
     * @return map 消息类型和消息类型对应的content数据
     */
    public static <T> CommonObj<T> matchTypeRun(String type, String content) throws IOException {
        for (MsgTypeEnum item : MsgTypeEnum.values()) {
            if (item.type.equals(type)) {
                CommonObj<T> commonObj = new CommonObj<>();
                commonObj.setCode(ErrorCode.SUCCESS.code);
                commonObj.setSuccess(Boolean.TRUE);
                // 设置消息类型
                commonObj.setMessage(type);
                // 设置消息数据
                commonObj.setData(item.run(content));
                return commonObj;
            }
        }
        return new CommonObj<>(ErrorCode.FAIL.code, "获取消息数据失败", false);
    }

}

使用:

CommonObj<Object> msgContentObj = MsgTypeEnum.matchTypeRun(consumeMsg.getMsgType(), consumeMsg.getContent());

MsgTypeEnum中,我定义了一个抽象枚举方法run,在枚举类型中实现了run方法。

这里主要是根据传入的数据类型进行不同的反序列化,然后再返回。

demo2

可能上面的有泛型,为了方便各位理解,我再来一个没有泛型的,帮助各位理解一下。

import com.withive.project.tools.file.entity.DebugCorrelationFile;

/**
 * 文件关联的类型
 *
 * @author Zhaopo Liu
 */
public enum DbgFileType {

    /**
     * 设备参数
     */
    DEVICE_PARAMS(0) {
        @Override
        DebugCorrelationFile run(Long fileId, Long correlationId) {
            return DebugCorrelationFile.builder()
                    .fileId(fileId)
                    .deviceParamsId(correlationId)
                    .build();
        }
    },

    /**
     * 测量绕组连同套管的直流电阻
     */
    WINDING_TASK(1) {
        @Override
        DebugCorrelationFile run(Long fileId, Long correlationId) {
            return DebugCorrelationFile.builder()
                    .fileId(fileId)
                    .windingTaskId(correlationId)
                    .build();
        }
    },

    /**
     * 所有分接头的电压比及三相组别ID
     */
    TAP_THREE_TEST_TASK(2) {
        @Override
        DebugCorrelationFile run(Long fileId, Long correlationId) {
            return DebugCorrelationFile.builder()
                    .fileId(fileId)
                    .tapThreeTestTaskId(correlationId)
                    .build();
        }
    },

    /**
     * 绕组连同套管的绝缘电阻、吸收比或极化指数
     */
    WINDING_POLARIZATION_TASK(3) {
        @Override
        DebugCorrelationFile run(Long fileId, Long correlationId) {
            return DebugCorrelationFile.builder()
                    .fileId(fileId)
                    .windingPolarizationTaskId(correlationId)
                    .build();
        }
    },

    /**
     * 介质损耗及电容值测试
     */
    MEDIUM_CAPACITANCE_LOSS(4) {
        @Override
        DebugCorrelationFile run(Long fileId, Long correlationId) {
            return DebugCorrelationFile.builder()
                    .fileId(fileId)
                    .mediumCapacitanceLossId(correlationId)
                    .build();
        }
    },

    /**
     * 绕组连同套管的交流耐压试验
     */
    WINDING_AC_TASK(5) {
        @Override
        DebugCorrelationFile run(Long fileId, Long correlationId) {
            return DebugCorrelationFile.builder()
                    .fileId(fileId)
                    .windingAcTaskId(correlationId)
                    .build();
        }
    },

    /**
     * 与铁心绝缘的各紧固件及铁心的绝缘电阻
     */
    IRON_FASTENERS_INSULATION_TASK(6) {
        @Override
        DebugCorrelationFile run(Long fileId, Long correlationId) {
            return DebugCorrelationFile.builder()
                    .fileId(fileId)
                    .ironFastenersInsulationTaskId(correlationId)
                    .build();
        }
    },

    /**
     * 绕组变形(电抗法)
     */
    WINDING_DEFORMATION_TASK(7) {
        @Override
        DebugCorrelationFile run(Long fileId, Long correlationId) {
            return DebugCorrelationFile.builder()
                    .fileId(fileId)
                    .windingDeformationTaskId(correlationId)
                    .build();
        }
    },

    /**
     * 试验结论
     */
    DEBUG_TASK(8) {
        @Override
        DebugCorrelationFile run(Long fileId, Long correlationId) {
            return DebugCorrelationFile.builder()
                    .fileId(fileId)
                    .debugTaskId(correlationId)
                    .build();
        }
    };

    private Integer type;

    DbgFileType() {
    }

    DbgFileType(Integer type) {
        this.type = type;
    }

    public Integer getType() {
        return type;
    }

    public void setType(Integer type) {
        this.type = type;
    }

    /**
     * 定义抽象方法
     */
    abstract DebugCorrelationFile run(Long fileId, Long correlationId);

    /**
     * 比对消息类型,然后执行run方法,返回对应的DebugCorrelationFile{@link DebugCorrelationFile}
     *
     * @param dbgType 试验类型
     * @param fileId 文件ID
     * @param correlationId 哪个试验项目的ID
     * @return DebugCorrelationFile
     */
    public static DebugCorrelationFile matchTypeRun(Integer dbgType, Long fileId, Long correlationId) {
        for (DbgFileType item : DbgFileType.values()) {
            if (item.type.equals(dbgType)) {
                return item.run(fileId, correlationId);
            }
        }
        return null;
    }

}

DbgFileType中,我写了一个抽象方法run,它需要传入文件ID和实验项目的ID。

matchTypeRun中,我传入的参数就多了一个dbgType,也就是DbgFileType的枚举值,这里就将我前面说的match方法,传入枚举值,返回枚举类型,枚举类型中实现了我定义的抽象方法run,最终返回我需要的DebugCorrelationFile

使用demo:

DebugCorrelationFile debugCorrelationFile = DbgFileType.matchTypeRun(dbgFileTypeNum, entity.getId(), correlationId);
本文目录