Bootstrap

Java根据code获取枚举优化

需求

自己模拟两个枚举,假设业务中需要用到

Example1StatusEnum.java

package com.zdh.zdhenum;

/**
 * @author dh
 * @date 2024/07/24
 * @desc (详细信息)
 */
public enum Example1StatusEnum {
    NEW("new", "新建状态"),
    FAIL("fail", "失败状态"),
    SUCCESS("success", "成功状态"),
    CLOSED("closed", "关闭状态");

    private String code;

    private String description;

    Example1StatusEnum(String code, String description) {
        this.code = code;
        this.description = description;
    }
}

Example2StatusEnum .java

package com.zdh.zdhenum;

import com.fasterxml.jackson.databind.ser.Serializers;

/**
 * @author dh
 * @date 2024/07/24
 * @desc (详细信息)
 */
public enum Example2StatusEnum implements BaseEnum {
    NEW("new", "新建状态"),
    FAIL("fail", "失败状态"),
    SUCCESS("success", "成功状态"),
    PROCESSING("processing", "处理中状态"),
    WAITING("waiting", "等待状态"),
    CLOSED("closed", "关闭状态"),
    ABANDONED("abandoned", "弃状态");

    private String code;

    private String description;

    Example2StatusEnum(String code, String description) {
        this.code = code;
        this.description = description;
    }

}

实际场景中,可能远远大于2个,每个枚举类内item有唯一的code,实际业务开发中需要根据唯一的code获取对应的枚举类型。

原始解决方案

哪个枚举类需要根据code获取对应的枚举,就在该枚举类中添加获取方法

例如Example1StatusEnum 需要根据code获取对应的枚举,在Example1StatusEnum 添加如下方法:

public static Example1StatusEnum  toEnum(String code){
        for (Example1StatusEnum item : Example1StatusEnum.values()) {
            if (Objects.equals(item.getCode(),code)) {
                return item;
            }
        }
        return null;
    }

同理,其他需要用到此方法,都需要复制上面的方法,并更改为对应类型,大量重复性工作。

优化方案

1. 首先创建base接口。

package com.zdh.zdhenum;

/**
 * @author dh
 * @date 2024/07/23
 * @desc (详细信息)
 */
public interface BaseEnum {
    /**
     * 获取code
     * @return
     */
    String getCode();
}

后面工具类根据此接口方法可以 通用的获取code

2. 创建枚举工具类

package com.zdh.zdhenum;

import java.util.Objects;

/**
 * @author dh
 * @date 2024/07/24
 * @desc (详细信息)
 */
public class MyEnumUtil {

    public static <E extends Enum<E> & BaseEnum> E toEnumByCode(String code, Class<E> enumClass) {
        for (E enumConstant : enumClass.getEnumConstants()) {
            if (Objects.equals(enumConstant.getCode(),code)) {
                return enumConstant;
            }
        }
        return null;
    }
}

<E extends Enum<E> & BaseEnum> 这里泛型,extends 表现必须继承自后面的xxx,BaseEnum规定必须实现上面定义的BaseEnum接口,Enum<E> 为枚举类的公共父类,规定必须是枚举类可以用此方法。

3. 需要使用工具类的枚举,实现BaseEnum接口即可

例如,Example1StatusEnumExample2StatusEnum都需要使用。

分别修改如下:

package com.zdh.zdhenum;

import java.util.Objects;

/**
 * @author dh
 * @date 2024/07/24
 * @desc (详细信息)
 */
public enum Example1StatusEnum implements BaseEnum{
    NEW("new", "新建状态"),
    FAIL("fail", "失败状态"),
    SUCCESS("success", "成功状态"),
    CLOSED("closed", "关闭状态");

    private String code;

    private String description;

    Example1StatusEnum(String code, String description) {
        this.code = code;
        this.description = description;
    }

    /**
     * 获取code
     *
     * @return
     */
    @Override
    public String getCode() {
        return this.code;
    }

}

package com.zdh.zdhenum;

import com.fasterxml.jackson.databind.ser.Serializers;

/**
 * @author dh
 * @date 2024/07/24
 * @desc (详细信息)
 */
public enum Example2StatusEnum implements BaseEnum {
    NEW("new", "新建状态"),
    FAIL("fail", "失败状态"),
    SUCCESS("success", "成功状态"),
    PROCESSING("processing", "处理中状态"),
    WAITING("waiting", "等待状态"),
    CLOSED("closed", "关闭状态"),
    ABANDONED("abandoned", "弃状态");

    private String code;

    private String description;

    Example2StatusEnum(String code, String description) {
        this.code = code;
        this.description = description;
    }

    /**
     * 获取code
     *
     * @return
     */
    @Override
    public String getCode() {
        return this.code;
    }
}

4. 测试使用

    public static void main(String[] args) {
        Example1StatusEnum quotaStatusEnum11 = MyEnumUtil.toEnumByCode("new", Example1StatusEnum.class);
        System.out.println("quotaStatusEnum11 = " + quotaStatusEnum11);
        Example1StatusEnum quotaStatusEnum12 = MyEnumUtil.toEnumByCode("fda", Example1StatusEnum.class);
        System.out.println("quotaStatusEnum12 = " + quotaStatusEnum12);

        Example2StatusEnum quotaStatusEnum21 = MyEnumUtil.toEnumByCode("new", Example2StatusEnum.class);
        System.out.println("quotaStatusEnum11 = " + quotaStatusEnum21);
        Example2StatusEnum quotaStatusEnum22 = MyEnumUtil.toEnumByCode("fda", Example2StatusEnum.class);
        System.out.println("quotaStatusEnum12 = " + quotaStatusEnum22);
    }

为了方便查看效果,可以在最后打个断点。
在这里插入图片描述

查看结果,发现和预期一样

在这里插入图片描述

拓展

假设,可能需要根据description 获取枚举,实际场景可能遇不到,重点在于思想。

那么几种解决方案:

  1. 原有的BaseEnum接口上加一个String getDescription(),然后MyEnumUtil 中添加一个和toEnumByCode类似的方法,泛型中依然使用BaseEnum。
  2. 新建一个接口BaseDescEnum,里面就一个String getDescription()方法。然后MyEnumUtil 中添加一个和toEnumByCode类似的方法,泛型中使用新的BaseDescEnum。

这里我建议使用第2种方法,这样颗粒度更细。第1种就算不需要根据description 获取枚举,也要实现String getDescription方法(虽然1.8之后可以通default关键字在接口默认实现,但是个人不太建议此场景这么使用)。

下面简单说一下实现。
新增BaseDescEnum接口

package com.zdh.zdhenum;

/**
 * @author dh
 * @date 2024/07/23
 * @desc (详细信息)
 */
public interface BaseDescEnum {
    /**
     * 获取description
     * @return
     */
    String getDescription();
}

假设仅仅Example1StatusEnum需要,代码修改如下:

package com.zdh.zdhenum;

import java.util.Objects;

/**
 * @author developer_ZhangXinHua
 * @date 2024/07/24
 * @desc (详细信息)
 */
public enum Example1StatusEnum implements BaseEnum,BaseDescEnum{
    NEW("new", "新建状态"),
    FAIL("fail", "失败状态"),
    SUCCESS("success", "成功状态"),
    CLOSED("closed", "关闭状态");

    private String code;

    private String description;

    Example1StatusEnum(String code, String description) {
        this.code = code;
        this.description = description;
    }

    /**
     * 获取code
     *
     * @return
     */
    @Override
    public String getCode() {
        return this.code;
    }


    /**
     * 获取description
     *
     * @return
     */
    @Override
    public String getDescription() {
        return this.description;
    }
}

MyEnumUtil中添加如下方法

  public static <E extends Enum<E> & BaseDescEnum> E toEnumByDesc(String desc, Class<E> enumClass) {
        for (E enumConstant : enumClass.getEnumConstants()) {
            if (Objects.equals(enumConstant.getDescription(),code)) {
                return enumConstant;
            }
        }
        return null;
    }

调用

public static void main(String[] args) {
        Example1StatusEnum quotaStatusEnum11 = MyEnumUtil.toEnumByCode("new", Example1StatusEnum.class);
        System.out.println("quotaStatusEnum11 = " + quotaStatusEnum11);
        Example1StatusEnum quotaStatusEnum12 = MyEnumUtil.toEnumByCode("processing", Example1StatusEnum.class);
        System.out.println("quotaStatusEnum12 = " + quotaStatusEnum12);

        Example2StatusEnum quotaStatusEnum21 = MyEnumUtil.toEnumByCode("processing", Example2StatusEnum.class);
        System.out.println("quotaStatusEnum11 = " + quotaStatusEnum21);
        Example2StatusEnum quotaStatusEnum22 = MyEnumUtil.toEnumByCode("fda", Example2StatusEnum.class);
        System.out.println("quotaStatusEnum12 = " + quotaStatusEnum22);

        Example1StatusEnum enumByDesc11 = MyEnumUtil.toEnumByDesc("新建状态", Example1StatusEnum.class);
        System.out.println("enumByDesc11 = " + enumByDesc11);
        Example1StatusEnum enumByDesc12 = MyEnumUtil.toEnumByDesc("xfdas", Example1StatusEnum.class);
        System.out.println("enumByDesc12 = " + enumByDesc12);
//        Example1StatusEnum enumByDesc13 = MyEnumUtil.toEnumByDesc("新建状态", Example2StatusEnum.class);
//        System.out.println("enumByDesc13 = " + enumByDesc13);
    }

发现如果Example2StatusEnum没有实现BaseDescEnum,连编译都不能通过。为什么上文不建议使用default,这样如果别人不熟悉实现,使用我们的工具类,可以强制让使用该工具类的人员,必须通过BaseDescEnum实现进行重写getDescription,防止忘记重写getDescription,从而获取到错误的description。
在这里插入图片描述
正常获取。
在这里插入图片描述
至此,优化完成。🎉🎊

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;