小Tips-枚举Enum的进阶用法

1、简介

枚举的基础使用不需要多说,本篇讲述的是进阶使用。

对于枚举的定义,类似接口但是有自己的构造方法,枚举不可以使用extends继承关键字,但是可以实现接口,特点描述如下

  • 枚举不可以继承
  • 可以实现接口
  • 可以有抽象方法

2、枚举与字典

字典:通常用于维护可变少,无流程的常量,存储在数据库中

  • 一般用于存储如性别、是否、开关等

枚举:不可变常量,每一种状态可能都会影响到流程,存储在java代码中

  • 如订单的状态,使用的是枚举存储

3、枚举-接口与lombok的结合使用

lombok的@Getter注解简化了属性的get()方法,interface定义get方法的规则
因此需要统一枚举的属性,定义枚举需要实现的公共接口

定义接口 FlowBaseEnum.class

1
2
3
4
5
6
7
public interface FlowBaseEnum {

String getKey();

String getValue();

}

枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 设备绑定状态枚举
* @author wuhao
* @date 2022/11/1 15:25
*/
@Getter
@AllArgsConstructor
public enum DeviceBindStatus implements FlowBaseEnum {

LOCKED("1","锁定"),

UNLOCKED("2","未锁定"),
;

private final String key;

private final String value;

}

上述枚举 属性 key value为固定字段,接口方法为属性的get方法

4、接口的作用

单个枚举的使用看不出接口的效果,对于接口的定义,通过接口来统一的管理流程类枚举

应用场景:设备绑定状态下拉框数据

定义流程枚举工具类:FlowEnumUtils

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

/**
* @author wuhao
* @date 2022/11/4 16:34
*/
public class FlowEnumUtils {
/**
* 获取枚举下拉
*
* @param cls 枚举class类
* @param <T>
* @return
*/
public static <T extends FlowBaseEnum> List<OptionLabel<String, String>> getOptionList(Class<T> cls) {
Assert.notNull(cls);
T[] constants = cls.getEnumConstants();
return Arrays.stream(constants).map(t -> {
OptionLabel<String, String> optionLabel = new OptionLabel<>();
optionLabel.setLabel(t.getValue());
optionLabel.setValue(t.getKey());
return optionLabel;
}).collect(Collectors.toList());
}
}

OptionLabel为通用的下拉实体,只有label与value两个属性

这个方法可以看出来为什么要定义接口了吧

使用泛型,T的类型为FlowBaseEnum接口的实现类,当然实现类必须为枚举,不然cls.getEnumConstants()会报错,通过getEnumConstants()方法获取枚举数组,返回的就是枚举中所有的构造方法,通过接口定义的getKey()与getValue()获取key value封装成下拉实体。

因此定义接口是为了统一维护枚举,并加以扩展定制化

5、枚举的分组

场景:不同订单类型下,订单中的数据类型不相同。
如订单类型分为

  • 修复类型订单
  • 种植类型订单
  • 正畸类型订单

每个类型中所对应的数据是不相同的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/** 
* 订单数据类型接口
* @author wuhao
* @date 2022/11/1 18:12
*/
public interface IOrderDataTypes {

/**
* 修复类型
*/
@Getter
@AllArgsConstructor
enum REPAIR implements IOrderDataTypes {
DATA_INTACT("数据完整性"),
MARGIN("边缘"),
RECESSED_AND_POSITION_PATH("倒凹&就位道"),
;

private final String description;
}

/**
* 种植类型
*/
@Getter
@AllArgsConstructor
enum PLANT implements IOrderDataTypes {
DATA_INTACT("数据完整性"),
PLANTING_SCANNING_ROD("种植扫描杆"),
;
private final String description;
}

/**
* 正畸类型
*/
@Getter
@AllArgsConstructor
enum ORTHODONTICS implements IOrderDataTypes {
DATA_INTACT("数据完整性"),
BITE_THE_JAW("咬颌"),
;

private final String description;
}

}

接口中可定义多个枚举类,这里接口的作用仅仅是做一个分组的作用

6、枚举中的一对多分组

这里结合的是上面两种方式的一个进阶,相当于对枚举分组的一个实现,使用场景:
每个订单类型下,对应多个不同的数据类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
* 订单数据类型
* @author wyj
* @date 2022/11/1 17:46
*/
@Getter
@AllArgsConstructor
public enum OrderDataType implements FlowBaseEnum {

REPAIR("1","牙齿修复"){
@Override
public List<IOrderDataTypes.REPAIR> getOrderTypes() {
return Arrays.stream(IOrderDataTypes.REPAIR.values()).collect(Collectors.toList());
}
},

PLANT("2","牙齿种植"){
@Override
public List<IOrderDataTypes.PLANT> getOrderTypes() {
return Arrays.stream(IOrderDataTypes.PLANT.values()).collect(Collectors.toList());
}
},

ORTHODONTICS("3","牙齿正畸"){
@Override
public List<IOrderDataTypes.ORTHODONTICS> getOrderTypes() {
return Arrays.stream(IOrderDataTypes.ORTHODONTICS.values()).collect(Collectors.toList());
}
},

;

private final String key;

private final String value;

/**
* 获取类型中的详细类型
* @return
*/
public abstract <T extends IOrderDataTypes> List<T> getOrderTypes();
}

这里OrderDataType枚举中定义了3中订单类型,而如果需要实现每种类型对应多个数据类型,则需要定义一个抽象方法,返回的是数据类型列表,方法的返回值数据类型则是IOrderDataTypes的实现类。在上面枚举的分组中已经定义了一个IOrderDataTypes

1
2
3
4
// 要获取某一个类型中的数据类型列表
// 获取牙齿正畸订单数据类型列表标识
List<IOrderDataTypes> orderTypes = OrderDataType.ORTHODONTICS.getOrderTypes();
orderTypes.forEach(System.out::println);

图片.png

可以把枚举定义成接口,枚举中定义的值为接口的实现类,枚举中只能定义抽象方法,不能定义普通方法,而实现类中必须实现抽象方法

总结

了解枚举与字典的使用场景,可以是开发变的更高效,以前使用字典维护项目中的流程状态,开发起来很繁琐,因此关于流程的状态个人觉得不太适合使用字典维护。

灵感来自书籍《On Java 8 进阶版》


小Tips-枚举Enum的进阶用法
http://www.codersand.fun/2023/04/21/course/枚举Enum的进阶用法/
作者
吴昊
发布于
2023年4月21日
许可协议