我正在参加「掘金·启航计划」
前言
本篇文章是本人在工作过程中对枚举的一些实践以及看法,类似于个人规范,所以也不是适用于所有人,下面的内容偏向基础,望各位看客轻喷,如果有不同的想法,也可以在评论区指出。
枚举可以帮你做什么?或者说为什么要使用枚举
关于这一点我想通过2种场景来说明。
- 方法参数采用枚举作为参数。
- 运用到逻辑代码中。
方法参数采用枚举作为参数。
使用枚举作为方法参数,其作用我觉得有两个。
- 可以限制调用方乱输数值导致方法本身报错。
- 调用方不用关心传参数是否传错了。
这里我举一个栗子,有一个业务场景是这样的,我需要调用一个公用的编码生成器,其生成规则有很多,例如直接用UUID、雪花Id、自增数字或者生成的年月日+自增数、公司流水号+年月日等等的自定义规则。这个时候,我们写方法有两种形式。
- 每一种规则都写一个方法,这样方法偏向单一原则且比较好维护。但缺点在于写完后,方法比较多,调用方需要自己从多种方法中找到自己想用的。
/**
* 编码生成器
*/
public interface CodeRuleService {
/**
* 生成UUID
* @return
*/
String generateUUID();
/**
* 生成雪花Id
* @return
*/
String generateSnowflake();
/**
* 生成自增Id
* @return
*/
String generateIncrementId();
/**
* 生成公司流水号+年月日
* @return
*/
String generateSerialNumber();
/**
* 生成公司内部自定义的编码
* @return
*/
String generateCustomNumber();
//.........
//.........
// .......
//等等的生成规则,如果再加上除了编码生成的方法以外的的方法,例如校验编码、
//修改编码生成规则等等,那想必会有很多的方法
}
- 第二种就是写一个统一方法,然后有一个参数是类型参数,用来区分要生成的是哪种类型的编号
/**
* 统一的生成编码方法
* @param generateType 生成类型 1.UUID 2.雪花Id 3.自增Id 4.公司流水号+年月日 5,公司内部自定义的编码
* @return
*/
String generate(Integer generateType);
这里我讨论第二种方法的优化方案,也就是使用枚举去替代Integer参数。 如果使用上面代码进行编写的话,那么就有可能会出现以下的情况。
//可能因为业务原因,调用方传入了编写方本不允许的类型数值
codeRuleService.generate(114514);
//这个看起来是调用成功了,但是其他人看这段代码的时候,没法一眼明了是生成什么类型的Id
codeRuleService.generate(1);
这里体现出了两种坏处,编写方无法预测参数的数值以及编写调用方法的时候,无法清晰的表达要做什么
(当然,这两种坏处也可以使用其他方法解决,一个是if判断,一个是注释的方式)。
如果我们使用的是枚举值作为参数的话,那么避免出现以上这种情况。
/**
* 统一的生成编码方法
* @param generateType 生成类型 1.UUID 2.雪花Id 3.自增Id 4.公司流水号+年月日 5,公司内部自定义的编码
* @return
*/
String generate(CodeGenerateTypeEnum generateType);
调用方式
//没法传入枚举本身不存在的类型
codeRuleService.generate(CodeGenerateTypeEnum.DFAHUWE);
//这里可以清晰的看到要生成的是UUID类型的编码
codeRuleService.generate(CodeGenerateTypeEnum.UUID);
这里除了可以避免上面两种坏处,其实还有一种好处,也就是统一管理,这个我们讲第二种场景的时候说明。
运用到逻辑代码中
运用到逻辑代码中,会重点突出两种好处,第一个是清晰,第二种是统一管理。下面我写一段代码
Integer codeGenerateType=0;
//根据编码类型处理事情
switch (codeGenerateType){
case 1:
//do something
break;
case 2:
//do something
break;
case 3:
//do something
break;
case 4:
//do something
break;
case 5:
//do something
break;
default:
break;
}
上面这样写并没有什么问题,只是以后要改你代码的人看这段代码的时候需要费多一点时间来理解你的代码。
CodeGenerateTypeEnum codeGenerateType=CodeGenerateTypeEnum.CUSTOM_NUMBER;
//生成规则
switch (codeGenerateType){
case UUID:
//do something
break;
case SNOWFLAKE:
//do something
break;
case INCREMENT:
//do something
break;
case SERIAL_NUMBER:
//do something
break;
case CUSTOM_NUMBER:
//do something
break;
default:
break;
}
这样写至少会比一开始写的要清晰许多。而且如果保持一开始的写法的话,一旦类型值改动的话,所有用到这个类型的地方都需要进行修改(会比较难找,因为不会有报错信息) 如果我们用枚举类型的话,就只需要修改枚举类型对应的值就可以了,无需改动其他应用的部分。 这里体现了枚举的统一管理。
总结
总的来说,使用枚举有三点好处,限制、清晰、统一管理,不好的地方嘛,那估计是会存在挺多的枚举类,还有考验枚举的命名,比较命名不好,调用方还是会花时间去查看是什么意思。