你有被if-else支配过吗?看完这篇文章,你就知道该怎么做

在日常工作中,如果让你碰到一大堆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<StringString> handleMap = ImmutableMap.<StringString>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语句出现,避免给自己以及其他阅读代码的人带来困扰(说的是你,小张)。

如果这篇文章有给您带来帮助或者对这篇文章比较感兴趣,麻烦给点一个免费的关注。

谢谢,再会~~

posted @   程序员浅梦  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示