在日常工作中,如果让你碰到一大堆if-else嵌套的代码,你会怎么做?
背景
最近在给之前负责的项目做CR的时候,在项目代码中发现有大量的if-else判断语句,阅读起来非常的折磨人而且也不利于后期的维护扩展,比较容易出问题。当时我直接气血上涌,差点昏过去。 缓过几分钟之后,把写这段代码的小张叫了过来,准备跟他好好聊聊。
我: 这块业务代码怎么这么多if-else语句判断,为什么要这么写?有没有想过代码规范或者该怎么去优化这段代码?
小张: 我根据自己对需求的理解,就直接上手写代码了,也没考虑过代码规范这些东西。
好嘛,年轻人到底是年轻人,做事情还得慢慢教。好好看好好学,下次再写代码时多注意代码规范,应当要避免此类问题。
教学时间开始
提前终止不符合的条件
首先,相信大部分小伙伴在写业务代码时,需要去做一些条件的校验(别告诉我你不做),就像下面的这段代码:
private static void handleValueByDto(Dto dto) {
if (flagA) {
A a = handleMethodA(dto);
if (flagB) {
B b = handleMethodB(a);
}
}
}
这段代码看上去还行,那么假如在来几个if嵌套呢,要蚌埠住了吧?那么要怎么做呢?你可以这么去做,将不符合的条件提前终止,符合条件的继续处理,就像下面这段代码:
private static void handleValueByDto(Dto dto) {
if (!flagA) {
// 这里可以加上日志,方便后续排查
return;
}
A a = handleMethodA(dto);
if (!flagB) {
// 这里可以加上日志,方便后续排查
return;
}
B b = handleMethodB(a);
}
优化过后的代码看上去更加优雅,而且也不会让人血压飙升。
三目运算符赋值
三目运算符我在日常工作中也经常用到,一方面可以将代码精简到一行,减少代码量,另外一方面,使用三目运算符更容易让别人理解。比如说:
A a = new A();
a.setGroup(StringUtils.isBlank(s) ? "1" : "2")
使用Optional解决判空
如果代码中某个属性值需要做判空处理,那么在Java8之后的版本,你可以使用Optional来处理,也能够避免大量的if-else语句。比如说:
public static String handleValueByDto(String a) {
if (a != null) {
handleMethod(a);
} else {
return null;
}
}
或者是
public static String handleValueByDto(String a) {
if (a == null) {
return null;
}
handleMethod(a);
}
上面的第二部分代码貌似也能接受,不过有更好的解决方案为何不用呢?
public static String handleValueByDto(String a) {
return Optional.ofNullable(a)
.map(v -> handleMethod(a)).orElse(null);
}
经过这么一对比,你更愿意用哪一种方案来解决判空呢?
使用枚举来优化
根据枚举值执行不同的操作,这一点针对if-else也能起到很不错的效果,具体操作如下:
public enum HandleTypeEnum {
TYPE_A(1) {
protected Byte getHandle() {
return 1;
}
},
TYPE_B(2) {
protected Byte getHandle() {
return 2;
}
},
TYPE_C(3) {
protected Byte getHandle() {
return 3;
}
};
public Byte type;
HandleTypeEnum(Byte type) {this.type = type;}
public static HandleTypeEnum handleByType(Byte type) {
return Arrays.stream(HandleTypeEnum.values())
.filter(a -> a.type.equals(type))
.findFirst().orElse(null);
}
protected abstract Byte getHandle();
}
private static Byte getHandle(Byte type) {
HandleTypeEnum handleType = HandleTypeEnum.handleByType(type);
return handleType.getHandle();
}
使用Map
使用Map来优化if-else要注意的是,创建一个额外的map会占用服务内存,并且需要考虑清楚是否要使用这种方式来进行优化。实现方式比较简单,像下面这段代码:
public static final Map<String, String> handleMap = ImmutableMap.<String, String>builder()
.put("A", "处理A")
.put("B", "处理B")
.put("C", "处理C")
.build();
使用的时候也非常简单,就是直接通过定义的map根据key获取相应的处理方法,例如:
public String handleByType(String type) {
return handleMap.get(type);
}
策略模式
这个方案我在之前做过的项目中有使用过,具体操作就是将每一个条件单独抽离成一个策略类,在主业务流程中使用策略类执行相关逻辑。这种方案的好处就是能够降低代码耦合,比较利于后续维护以及业务扩展,并且也容易被理解。 比如说,电商系统下单业务,会涉及到不同的折扣方案,根据对应的折扣方案实现折扣减免,那么使用策略模式该怎么做呢?先定义一个策略接口
public interface CouponDiscount<T> {
/**
* 判断该策略是否支持
*/
Boolean support(BigDecimal price);
BigDecimal discountAmount(BigDecimal skuPrice, T coupon);
}
然后根据具体的折扣方案实现上面的策略接口:
public class ACouponDiscount implements CouponDiscount<Double> {
public Boolean support(BigDecimal price) {
return price < 300;
}
public BigDecimal discountAmount(BigDecimal skuPrice, Double coupon) {
// TODO: 实现折扣A业务处理逻辑
}
}
public class BCouponDiscount implements CouponDiscount<Double> {
public Boolean support(BigDecimal price) {
return price > 500;
}
public BigDecimal discountAmount(BigDecimal skuPrice, Double coupon) {
// TODO: 实现折扣B业务处理逻辑
}
}
最终调用模块中进行简单配置:
public class CouponDiscountService {
@Autowired
private static List<CouponDiscount> list;
public BigDecimal discountAmount(int type, double coupon, double skuPrice) {
for (CouponDiscount v : list) {
// 这里如果满足条件, 那么就使用该策略,不满足继续循环
if (v.support(skuPrice)) {
return v.discountAmount(skuPrice, coupon)
}
}
}
}
我也注意到网上有非常多的文章在讲策略模式+工厂模式解决if-else的问题,但那种方式的前提是,明确知道有哪些策略存在。并且如果后续增加其它策略,意味着要改动策略工厂的代码,违背了开闭原则,所以不是很好。
最后总结
上面的几种方案在优化if-else方面有非常不错的效果,根据实际情况选择对应的方案来处理。不过最重要的一点就是,在编码阶段需要注意开发规范,尽量减少大量的if-else语句出现,避免给自己以及其他阅读代码的人带来困扰(说的是你,小张)。
如果这篇文章有给您带来帮助或者对这篇文章比较感兴趣,麻烦给点一个免费的关注。
谢谢,再会~~
标签:支配,return,BigDecimal,代码,else,篇文章,type,public From: https://www.cnblogs.com/c-shallow-dream/p/17970061