前言:一个业务类型或者一个属性标识都可以用枚举来表示,这是一种很好地记录业务能力的方式。但是当这种情况很多时,就会发现每一个业务都需要匹配枚举。这时候,可以把共性的东西提炼出来,作为一个通用能力,支撑千变万化的业务场景。
目录
§ 1.现状
public enum TestEnum {
STEP_1("测试1"),
STEP_2("测试2"),
STEP_3("测试23");
/** 描述 */
private String desc;
TestEnum(String desc) {
this.desc = desc;
}
public String getDesc() {
return desc;
}
public TestEnum getEnum(String key){
if (key == null) {
return null;
}
for (TestEnum testEnum:TestEnum.values()){
if (testEnum.getDesc().equals(key)) {
return testEnum;
}
}
return null;
}
}
平常基本的枚举会如上所写,当需要满足某个条件的枚举时候,需要写这种重复功能的工作,可以看到上面的代码单个看是没有问题,但是当业务场景一多,这种匹配会出现很多,对于枚举的获取方式也需要一种通用的获取来减少代码的重复度和增加功能的复用性,所以提供一种通用函数式枚举,来解决如下出现的问题。
出现问题
§ 2.适合场景
§ 3.通用方法
根据上面思路,单个匹配场景,按是否二次加工划分getEnum和getEnumFun,可以看到带有Fun的是支持二次加工的,不带直接返回结果。多个匹配场景,按是否加工划分getEnums和getEnumsFun。输入也可以划分为,按单个值code匹配,按自定义条件匹配Predicate<E>需要的枚举,满足精确匹配和自定义匹配方式。
import java.util.EnumSet;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* 公共枚举接口
*
* @author 北城微雨
*/
public interface CommonEnum<T> {
/**
* 获取code值
*
* @return
*/
T getCode();
/**
* 单个code精确匹配单个枚举,直接返回枚举
*
* @param code 枚举code
* @param clazz 枚举实体类
* @param <T> code的类型
* @param <E> 枚举类型
* @return 返回对应枚举
*/
static <T, E extends Enum<E> & CommonEnum> E getEnum(T code, Class<E> clazz) {
return getEnum(a -> Objects.equals(a.getCode(), code), clazz);
}
/**
* 单个code精确匹配单个枚举,枚举二次处理
*
* @param code 枚举code
* @param clazz 实体类
* @param function 二次函数处理
* @param <E> 枚举类型
* @param <N> 返回类型
* @return 返回二次处理枚举
*/
static <N, T, E extends Enum<E> & CommonEnum> N getEnumFun(T code, Class<E> clazz, Function<E, N> function) {
return getEnumFun(a -> Objects.equals(a.getCode(), code), clazz, function);
}
/**
* 指定条件匹配单个枚举,直接返回枚举
*
* @param predicate 判断条件
* @param clazz 实体类
* @param <E> 枚举类型
* @return 返回二次处理枚举
*/
static <E extends Enum<E> & CommonEnum> E getEnum(Predicate<E> predicate, Class<E> clazz) {
EnumSet<E> all = EnumSet.allOf(clazz);
return all.stream().filter(predicate).findFirst().orElse(null);
}
/**
* 指定条件匹配单个枚举,枚举二次处理
*
* @param predicate 判断条件
* @param clazz 实体类
* @param function 二次函数处理
* @param <E> 枚举类型
* @param <N> 返回类型
* @return 返回二次处理枚举
*/
static <N, E extends Enum<E> & CommonEnum> N getEnumFun(Predicate<E> predicate, Class<E> clazz, Function<E, N> function) {
EnumSet<E> all = EnumSet.allOf(clazz);
return all.stream().filter(predicate).findFirst().map(function).orElse(null);
}
/**
* 指定条件匹配单个枚举,直接返回枚举
*
* @param predicate 判断条件
* @param clazz 实体类
* @param <E> 枚举类型
* @return 返回枚举集合
*/
static <E extends Enum<E> & CommonEnum> List<E> getEnums(Predicate<E> predicate, Class<E> clazz) {
EnumSet<E> all = EnumSet.allOf(clazz);
return all.stream().filter(predicate).collect(Collectors.toList());
}
/**
* 指定条件匹配单个枚举,枚举二次处理
*
* @param predicate 判断条件
* @param clazz 实体类
* @param function 二次函数处理
* @param <E> 枚举类型
* @param <N> 返回类型
* @return 返回二次处理枚举集合
*/
static <N, E extends Enum<E> & CommonEnum> List<N> getEnumsFun(Predicate<E> predicate, Class<E> clazz, Function<E, N> function) {
EnumSet<E> all = EnumSet.allOf(clazz);
return all.stream().filter(predicate).map(function).collect(Collectors.toList());
}
}
§ 4.如何使用
@Getter
@AllArgsConstructor
public enum TestEnum implements CommonEnum<String> {
STEP_1("测试1"),
STEP_2("测试2"),
STEP_3("测试23");
/** 描述 */
private String code;
}
第一步需要继承CommonEnum<String>这个类,并且指定泛型是String,这个类就具备通用枚举业务方式,可以使用CommonEnum调用通用方法使用,具体有以下案例参考
4.1 有匹配案例
@Test
public void testEnum() {
//方式一:单个code精确匹配单个枚举/数据
TestEnum testEnum10 = CommonEnum.getEnum("测试1", TestEnum.class);
String testEnum11Fun = CommonEnum.getEnumFun("测试1", TestEnum.class, TestEnum::getCode);
String testEnum12Fun = CommonEnum.getEnumFun("测试1", TestEnum.class, test -> test.getCode() + " => 方式一.二次处理");
System.out.println("方式一:单个code精确匹配单个枚举/数据\n");
System.out.println("方式一.直接返回:" + testEnum10);
System.out.println("方式一.二次处理取code:" + testEnum11Fun);
System.out.println("方式一.二次处理:" + testEnum12Fun);
System.out.println("--------------------------------------");
//方式二:指定匹配条件返回单个枚举/数据
TestEnum testEnum20 = CommonEnum.getEnum(test -> test.getCode().contains("2"), TestEnum.class);
String testEnum21Fun = CommonEnum.getEnumFun(test -> test.getCode().contains("2"), TestEnum.class, test -> test.getCode() + " => 方式一.二次处理");
System.out.println("方式二:指定匹配条件返回单个枚举/数据\n");
System.out.println("方式二.直接返回:" + testEnum20);
System.out.println("方式二.二次处理:" + testEnum21Fun);
System.out.println("--------------------------------------");
//方式三:指定匹配条件返回多个枚举/数据
List<TestEnum> testEnum30 = CommonEnum.getEnums(test -> test.getCode().contains("2"), TestEnum.class);
List<String> testEnum31Fun = CommonEnum.getEnumsFun(test -> test.getCode().contains("2"), TestEnum.class, test -> test.getCode() + "Test");
System.out.println("方式三:指定匹配条件返回多个枚举/数据\n");
System.out.println("方式三.直接返回:" + testEnum30);
System.out.println("方式三.二次处理:" + testEnum31Fun);
}
【控制台结果】
可以明显看到方式一返回了指定数据,而方式二匹配数字 2 时候,其实是有 2 个可以匹配上的,但是因为findFirst(),所以返回第一个匹配上的,这种枚举方式可以极大的简化业务开发的枚举获取方式,更具有通用性,对于获取枚举中某一值,可直接返回对应的值即可,不需要二次取值的代码,简化业务的操作。对于需要匹配多个时候也支持返回结果和二次加工处理,适用更多的场景。
4.2 无匹配案例
@Test
public void testEnum() {
//方式一:单个code精确匹配单个枚举/数据
TestEnum testEnum10 = CommonEnum.getEnum("测试4", TestEnum.class);
String testEnum11Fun = CommonEnum.getEnumFun("测试4", TestEnum.class, TestEnum::getCode);
String testEnum12Fun = CommonEnum.getEnumFun("测试4", TestEnum.class, test -> test.getCode() + " => 方式一.二次处理");
System.out.println("方式一:单个code精确匹配单个枚举/数据\n");
System.out.println("方式一.直接返回:" + testEnum10);
System.out.println("方式一.二次处理取code:" + testEnum11Fun);
System.out.println("方式一.二次处理:" + testEnum12Fun);
System.out.println("--------------------------------------");
//方式二:指定匹配条件返回单个枚举/数据
TestEnum testEnum20 = CommonEnum.getEnum(test -> test.getCode().contains("4"), TestEnum.class);
String testEnum21Fun = CommonEnum.getEnumFun(test -> test.getCode().contains("4"), TestEnum.class, test -> test.getCode() + " => 方式一.二次处理");
System.out.println("方式二:指定匹配条件返回单个枚举/数据\n");
System.out.println("方式二.直接返回:" + testEnum20);
System.out.println("方式二.二次处理:" + testEnum21Fun);
System.out.println("--------------------------------------");
//方式三:指定匹配条件返回多个枚举/数据
List<TestEnum> testEnum30 = CommonEnum.getEnums(test -> test.getCode().contains("4"), TestEnum.class);
List<String> testEnum31Fun = CommonEnum.getEnumsFun(test -> test.getCode().contains("4"), TestEnum.class, test -> test.getCode() + "Test");
System.out.println("方式三:指定匹配条件返回多个枚举/数据\n");
System.out.println("方式三.直接返回:" + testEnum30);
System.out.println("方式三.二次处理:" + testEnum31Fun);
}
【控制台结果】
没有匹配到值的场景,调整 测试1 => 测试4 和 2 => 4 ,在TestEnum中可以看到没有匹配的,程序执行控制台返回结果对于单个没有匹配返回null,没有多个匹配返回空集合,友好返回结果便于后续业务的判断和后续业务处理。