1、简介
枚举的基础使用不需要多说,本篇讲述的是进阶使用。
对于枚举的定义,类似接口但是有自己的构造方法,枚举不可以使用extends继承关键字,但是可以实现接口,特点描述如下
- 枚举不可以继承
- 可以实现接口
- 可以有抽象方法
2、枚举与字典
字典:通常用于维护可变少,无流程的常量,存储在数据库中
- 一般用于存储如性别、是否、开关等
枚举:不可变常量,每一种状态可能都会影响到流程,存储在java代码中
- 如订单的状态,使用的是枚举存储
3、枚举-接口与lombok的结合使用
lombok的@Getter注解简化了属性的get()方法,interface定义get方法的规则
因此需要统一枚举的属性,定义枚举需要实现的公共接口
定义接口 FlowBaseEnum.class
public interface FlowBaseEnum {
String getKey();
String getValue();
}
设备绑定状态枚举类
/**
* 设备绑定状态枚举
* @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
/**
* @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、枚举的分组
场景:不同订单类型下,订单中的数据类型不相同。
如订单类型分为
- 修复类型订单
- 种植类型订单
- 正畸类型订单
每个类型中所对应的数据是不相同的
/**
* 订单数据类型接口
* @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、枚举中的一对多分组
这里结合的是上面两种方式的一个进阶,相当于对枚举分组的一个实现,使用场景:
每个订单类型下,对应多个不同的数据类型
/**
* 订单数据类型
* @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
。
// 要获取某一个类型中的数据类型列表
// 获取牙齿正畸订单数据类型列表标识
List<IOrderDataTypes> orderTypes = OrderDataType.ORTHODONTICS.getOrderTypes();
orderTypes.forEach(System.out::println);
可以把枚举定义成接口,枚举中定义的值为接口的实现类,枚举中只能定义抽象方法,不能定义普通方法,而实现类中必须实现抽象方法
总结
了解枚举与字典的使用场景,可以是开发变的更高效,以前使用字典维护项目中的流程状态,开发起来很繁琐,因此关于流程的状态个人觉得不太适合使用字典维护。
灵感来自书籍《On Java 8 进阶版》
ps
没事可以来我的破站逛逛~~欢迎大家