枚举在项目中的使用场景

1,503 阅读4分钟

场景一

之前一个刚毕业参加工作的网友问我一个问题,想对一个集合排序

TYU5HAF.png

如上图,想根据 checkLineLocation 字段值排序这个集合。我毕竟已经工作一年多了,经验相对比他多,首先肯定要问排序规则是什么,总不可能使用 String 默认的字典排序。

他说按照这个图从左到右的顺序,左边墙、左拱腰、拱顶、右拱腰、右边墙。现在我们知道了排序规则,但是 checkLineLocation 是 String 类型的,有自己默认的排序规则,所以我们需要给这个字段建立一个映射关系,然后写另一个排序规则。那么我首先想到的就是使用枚举。

首先定义一个枚举类

    public enum LineLocationEnum {

        LOCATION_LEFT_WALL( "左边墙",1),
        LOCATION_LEFT_WAIST("左拱腰",2),
        LOCATION_TOP("拱顶",3),
        LOCATION_RIGHT_WAIST("右拱腰",4),
        LOCATION_RIGHT_WALL("右边墙",5);

        LineLocationEnum(String location,int sort){
          this.location = location;
          this.sort = sort;
        }

        @Getter
        private final String location;
        @Getter
        private final int sort;

        //根据位置获取排序值
        public static int getSortByLocation(String location) {
            return Arrays.stream(LineLocationEnum.values())
                    .filter(orderStatusEnum -> orderStatusEnum.getLocation().equals(location))
                    .map(LineLocationEnum::getSort)
                    .findFirst()
                    .orElse(0);
        }
    }

这样我们就给 checkLineLocation 关联上了排序规则 sort,并且提供了根据 location 获取排序值 sort 的方法 getSortByLocation。然后写代码测试

    public static void main(String[] args) {
        List<CheckDataReport> list = new ArrayList<CheckDataReport>(){{
                add(new CheckDataReport("拱顶"));
                add(new CheckDataReport("右边墙"));
                add(new CheckDataReport("左拱腰"));
                add(new CheckDataReport("左边墙"));
                add(new CheckDataReport("右拱腰"));
            }
        };
        //排序
        list.sort(Comparator.comparingInt(o -> LineLocationEnum.getSortByLocation(o.getCheckLineLocation())));
        System.out.println(list);
    }

这样排序问题就解决了,先使字段可以按照我们的规则排序,然后调用集合的 sort 方法,在实现的 comparator 接口匿名类中,使用我们的排序规则即可。

枚举的好处在于它可以使一些数字符号化,然后增强程序的可读性。 比如上述问题,我们也可以在程序中 new 一个 HashMap 存储对应的 sort 排序值,然后排序,但是代码繁多,可读性差。使用枚举代码量很少,而且定义好枚举,下次类似场景还可以复用。

场景二

工作中某些字段在数据库中存储的可能是数字代表具体中文描述,比如订单状态。

10:待支付,15:待支付尾款 20:待发货,30:待收货,40:已完成,50:已关闭,60退款中,70已退款

如果说是 web 列表,我们返回数字给前端也没问题,swagger 接口文档里面注释好即可

    @Schema(description = "子订单状态,10:待支付,20:待发货,30:待收货,40:已完成,50:已关闭,60:退款中,70:已退款")
    private Integer childOrderStatus;

但是有一种场景是 excel 导出,这个功能是和前端没什么关系的,后端直接就把 excel 的字节流返回给浏览器了,所以我们需要直接返回对应的描述。此时也可以使用枚举。

    @RequiredArgsConstructor
    public enum OrderStatusEnum {

        WAIT_PAY(10, "待支付"),
        //...其他状态
        
        public static String getDescByCode(Integer code) {
            return Arrays.stream(OrderStatusEnum.values())
                    .filter(orderStatusEnum -> orderStatusEnum.getCode().equals(code))
                    .map(OrderStatusEnum::getDesc)
                    .findFirst()
                    .orElse(StringUtils.EMPTY);
        }
    }

在组装 excel 返回实体类中直接使用 getDescByCode 拿到对应的订单状态描述即可。当然我们也可以不使用枚举,在设置订单状态的时候,在方法内使用 switch 结构判断一下也行

 switch (status) {
            case 10:
                //...
                break;
            case 15:
                //...
                break;
            case 20:
                 //...

这样代码量繁多,而且可读性没有使用枚举高,并且下次在其他方法内部还需要写这种代码。

封装工具类

你可能已经发现了,上面的 getDescByCode 方法是写在枚举类里面的,正常项目中枚举少说十几二十个吧,如果每个类都写这么一段重复代码,这就违背了 DRY(Dont Repeat Yourself)原则。所以我们可以封装一个工具类,先定义枚举接口

    public interface GenericEnum {
        Integer getCode();
        String getDesc();
    }

然后我们的枚举类实现这个接口即可,结合我们上篇说过的泛型 一文带你搞懂 Java 泛型 ,定义泛型方法

    public final class EnumUtils {
        /***
         * 根据code获取枚举
         */
        public static <T extends GenericEnum> T getEnumByCode(Integer code, Class<T> enumClass) {
            return Arrays.stream(enumClass.getEnumConstants())
            .filter(t -> t.getCode().equals(code))
            .findFirst().orElse(null);
        }

        /***
         * 根据code获取描述
         */
        public static <T extends GenericEnum> String getEnumDescByCode(Integer code, Class<T> enumClass) {
            return Arrays.stream(enumClass.getEnumConstants())
                    .filter(t -> t.getCode().equals(code))
                    .map(T::getDesc).findFirst()
                    .orElse(null);
        }
    }

结语

枚举适合的场景就是定义一组有限的集合,像颜色、状态、优惠券类型、快递运输状态等等都适合使用枚举。本篇文章列举了两个博主使用枚举的场景,以后有其他使用场景会继续更新过来。

如果这篇文章对你有帮助,记得点赞加关注。你的支持就是我继续创作的动力!