在程序开发中,if else是我们经常用到的条件判断语句。在程序逻辑中,免不了会有各种条件的判断,并根据结果执行对应的逻辑。if else的好处就是简单,可读性高。然而,随着判断条件变得复杂,判断条件越来越多,就不那么易读了。在一些老项目中,由于缺乏重构,容易出现if else过多太复杂,导致后来开发者不容易看懂因而不敢大改动,只敢在原来的逻辑上继续叠加if else,恶性循环。有句话叫做量变引起质变,时间久了最后成为一段能跑但看不懂改不动的烂代码。
在变成烂代码之前,趁还没到看不懂的地步,日常开发迭代中可以进行小步优化。下面将讲述几个比较常见的场景以及对应的优化方式。
if 条件判断过长
现象
重构书中的示例:
java
代码解读
复制代码
if (date.before(SUMMER_START) || date.after(SUMMER_END)) charge = quantity * this.winterRate + this.winterServiceCharge; else charge = quantity * this.summerRate;
该段逻辑中,if的判断条件是两个条件进行逻辑或进行组合,这种代码有个问题,可读性太差,无法理解业务含义。
解决方法
将很长的判断式封装成函数或者定义成宏,并以一个清晰表达意图的名字命名,名字能够体现出业务意义。
java
代码解读
复制代码
if (notSummer(date)) charge = winterCharge(quantity); else charge = summerCharge(quantity); private boolean notSummer(Date date) { return date.before(SUMMER_START) || date.after(SUMMER_END); } private winterCharge(int quantity) { return quantity * this.winterRate + this.winterServiceCharge; } private summerCharge(int quantity) { return quantity * this.summerRate; }
if 一系列条件测试,返回相同的结果
现象
继续借用重构中的示例:
kotlin
代码解读
复制代码
public String getStuLevel(int score) { if (score == 100) { return "A"; } else if (score >= 90) { return "A"; } else if (score >= 80) { return "B"; } else if (score >= 70) { return "B"; } else if (score >= 60) { return "C"; } else { return "D"; } }
score == 100和score >= 90都是返回A。
解决方法
将返回结果相同的分支进行合并处理。重构后代码如下所示:
kotlin
代码解读
复制代码
public String getStuLevel(int score) { if (score == 100 || score >= 90) { return "A"; } else if (score >= 80 || score >= 70) { return "B"; } else if (score >= 60) { return "C"; } else { return "D"; } }
if else 嵌套过深
现象
还是上个例子
java
代码解读
复制代码
if (condition1) { if (condition2) { action2(); } else { action1(); } } else { if (condition2) { action2(); } else { action3(); } }
这个例子中,if 里面还嵌套了if else。这个例子只是嵌套了两层,就已经不容易读了。真实项目中这个问题严重的多,个人这是对代码 可读性差的重要元凶。
解决方法
提前return。把一些场景提前return掉。优化后的代码如下:
java
代码解读
复制代码
if (condition2) { action2(); return; } if (condition1) { action1(); return; } action3();
项目中也有很多案例可以参考,if (不为空) {处理业务逻辑} 的可以先判断if (为空), 后面处理业务逻辑的{}就可以去掉了。 还有一些特殊的场景,可以提前return掉,这个需要对业务逻辑比较熟悉,重构时要小心。
显式路由转发
现象
if else中,还有种场景,if else中只有单层,没有嵌套,功能上只是做路由转发作用,这种情况使用if else的方式逻辑上也是很简单。
解决方法
如果想要代码看起来更美观,可以做成隐式映射,隐式映射有两种方法:枚举和Map方式。
枚举示例
来看一段代码
java
代码解读
复制代码
String orderStatusDes; if ("1".equals(orderStatus)) { orderStatusDes = "订单未支付"; } else if ("2".equals(orderStatus)) { orderStatusDes = "订单已支付"; } else if ("3".equals(orderStatus)) { orderStatusDes = "订单已发货"; } else if ("4".equals(orderStatus)) { orderStatusDes = "订单已签收"; } else if ("5".equals(orderStatus)) { orderStatusDes = "订单已评价"; }
这段代码中,功能是根据订单状态找到对应的订单状态描述。采用枚举的方式优化如下:
java
代码解读
复制代码
public enum OrderStatusEnum { UN_PAID("1","订单未支付"), PAIDED("2","订单已支付"), SENDED("3","订单已发货"), SINGED("4","订单已签收"), EVALUATED("5","订单已评价"); private String status; private String statusDes; static OrderStatusEnum of(String status) { for (OrderStatusEnum statusEnum : OrderStatusEnum.values()) { if (statusEnum.getStatus().equals(status)) { return statusEnum; } } return null; } }
java
代码解读
复制代码
String orderStatusDes = OrderStatusEnum.of(orderStatus).getStatusDes();
借用枚举的隐式映射特性,这段代码优化后一方面可续性上更加直观,订单状态和状态描述很直接就对应上;另一方面,代码也美观了好多,将映射的逻辑剥离出来放到枚举类中,外部调用一行代码就能解决。
Map映射示例
先来看一段代码
java
代码解读
复制代码
if (param.equals(value1)) { doAction1(someParams); } else if (param.equals(value2)) { doAction2(someParams); } else if (param.equals(value3)) { doAction3(someParams); } // ...
这段代码中根据value1值类型,路由不同的处理逻辑,来看如何用Map来优化。
java
代码解读
复制代码
/1. 先定义一个 ActionService 接口 public interface ActionService { void doAction(Context context); } //2. 然后定义 5 个实现类 public class ActionService1 implements ActionService{ public void doAction(Context context) { //do something } } //3. 加入表中 Map<String, ActionService> actionMap = new HashMap<>(); action.put("code1",new ActionService1()); action.put("code2",new ActionService2()); action.put("code3",new ActionService3()); action.put("code4",new ActionService4()); action.put("code5",new ActionService5()); //4. 调用 actionMap.get(action).doAction(someParams);
如果是spring项目,第3步可以从容器中自动找ActionService的实现类填充Map。