使用反射摆脱了过长的if/else校验
「这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战」
引言
最近做一个业务,需要做额度限制,超出额度做特殊业务处理,封装了一个方法专门做额度限制的校验,由于需要判断的金额字段太多导致if/else判断也随之增加,所以想到使用反射去做处理,减少代码量的同时,后续扩展性也比较强。
业务实体
下面是业务实体类,对字段名称做了特殊处理。
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ExpendLimit{
private BigDecimal count1Amt;
private BigDecimal count2Amt;
private BigDecimal count3Amt;
private BigDecimal count4Amt;
....
// 此处目前大概有12个金额字段需要做校验
}
复制代码
代码对比
封装方法使用两个参数,currentResidue表示当前剩余额度,currentTotal表示本期付款,逻辑为本期付款对象里如果count?Amt大于0,并且大于currentResidue对应字段的金额时,返回false,做超额逻辑处理。
使用反射前
private boolean checkResidue(ExpendLimit currentResidue, ExpendLimit currentTotal){
boolean result = true;
if (currentTotal.getCount1Amt().compareTo(BigDecimal.ZERO)>0){
if (currentTotal.getCount1Amt().compareTo(currentResidue.getCount1Amt())>0){
result = false;
}
} else if (currentTotal.getCount2Amt().compareTo(BigDecimal.ZERO)>0){
if (currentTotal.getCount2Amt().compareTo(currentResidue.getCount2Amt())>0){
result = false;
}
}...
// 如果写完全需要40多行,且如果后续业务增加需要继续加代码
return result;
}
复制代码
使用反射后
private boolean checkResidue(ExpendLimit currentResidue, ExpendLimit currentTotal) {
boolean result = true;
Class<? extends ExpendLimit> clazz = currentResidue.getClass();
Field[] fields = clazz.getDeclaredFields();
try {
for (Field field : fields) {
//打开私有访问
field.setAccessible(true);
//获取属性
String name = field.getName();
if (name.contains("Amt")) {
//获取属性值
BigDecimal totalAmt = (BigDecimal) field.get(currentTotal);
if (totalAmt.compareTo(BigDecimal.ZERO) > 0) {
BigDecimal residueAmt = (BigDecimal) field.get(currentResidue);
if (totalAmt.compareTo(residueAmt) > 0) {
result = false;
break;
}
}
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return result;
}
复制代码
反射的基本原理
- 编译阶段:编译期装载所有的类,将每个类的信息保存至Class类对象中,每一个类对应一个Class对象(不懂为啥每个类只有一个Class类对象的可以自己查询一下双亲委派模型)
- 获取Class对象:调用x.class/x.getClass()/Class.forName() 获取x的Class对象clz
- 使用反射进行操作:通过clz对象获取Field/Method/Constructor对象进行进一步操作。
反射使用的API
- java.lang.Class:代表一个类
- java.lang.reflect.Method:代表类的方法
- java.lang.reflect.Field:代表类成员变量
- java.lang.reflect.Constructor:代表类的构造器
反射提供的功能
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时获取泛型的信息
- 在运行时调用任意一个对象的成员变量和方法
- 在运行时处理注解
- 生成动态代理
总结
通过使用反射,改变了过长的if/else判断。在我的业务里其实只使用了java.lang.reflect.Field类获取对象属性做业务判断。其实反射在很多框架中都有使用,Spring的动态代理也是应用了反射,不管是CGLAB动态代理还是JDK动态代理其根本都是使用反射。
近期评论