代码整洁之道(一)之优化if-else的8种方案

我们日常开发的项目中,如果代码中存在大量的if-else语句,阅读起来非常的折磨(直接劝退),维护起来也很难,也特别容易出问题。比如说以下:

接下来,本文介绍我们常使用的8种方法去优化if-else。

希望这篇文章能对您有所启发。如果您觉得有价值,欢迎点赞或转载,并请记得注明出处

1、提前return,让正常流程走主干

如果if-else代码中包含return语句,或者我们可以将包含if-else的代码从主干中抽取到一个单独方法,这样就可以在这个方法中可以return掉。这中思想也是短路求值的一种体现。把多余 else 干掉,使代码更加优雅。

  • 优化前代码:
kotlin 复制代码
// 主流程代码  
if (condition){  
    // doSomething  
}else {  
    return;  
}
arduino 复制代码
// 主流程代码  
if (condition){  
// doSomething1  
}else {  
// doSomething2  
}
  • 优化后代码:
kotlin 复制代码
// 主流程代码  
if (!condition){  
    return;  
}  
 // doSomething
csharp 复制代码
// 主流程代码  
//doSomething  
doSomething();

private static void doSomething(){  
    // 主流程代码  
    if (!condition){  
    // doSomething1  
    return;  
    }  
    // doSomething2  
}

2、使用三目运算符

某些if-else可以优化为使用三目运算符,这样会让代码更简洁,可读性高。

  • 优化前
ini 复制代码
int price;  
if (condition1){  
    price = 1;  
} else if (condition2) {  
    price = 2;  
}else {  
    price = 0;  
}
  • 优化后
ini 复制代码
int price = condition1 ? 1 : (condition2 ? 2 : 0);

3、使用Optional

我们在代码中判null会导致存在大量的if-else,这个时候我们可以考虑使用Java8的Optional去优化。

  • 优化前
typescript 复制代码
public static void main(String[] args) {  
    String s = handleStr("11");  
    System.out.println(s);  
}  

private static String handleStr(String str){  
    if (str != null){  
    return str.concat("。。。。。");  
    }else {  
    return "Null";  
    }  
}
  • 优化后代码:
typescript 复制代码
public static void main(String[] args) {
    String s = Optional.ofNullable(handleStr("11"))
                       .map(str -> str.concat("。。。。。"))
                       .orElse("Null");

    System.out.println(s);
}

private static String handleStr(String str) {
    // 其余业务逻辑,同样适用于处理一个对象,判null
    return str;
}

4、多态

我们可以将一些操作(比如一些状态)的一些共性的方法抽象成一个公共接口,然后针对这些操作实现这些接口完成不同的逻辑,在调用时我们只需要传入对应的操作类即可,对外的操作方法都是同一个。

  • 优化前代码
csharp 复制代码
public class OrderProcessing {
    public static void main(String[] args) {
        processOrder("pending");
        processOrder("paid");
        processOrder("shipped");
    }

    private static void processOrder(String status) {
        if ("pending".equalsIgnoreCase(status)) {
            System.out.println("Handling payment for pending order.");
            // 处理支付逻辑
            System.out.println("Payment handled.");
            System.out.println("Cannot ship. Payment pending.");
        } else if ("paid".equalsIgnoreCase(status)) {
            System.out.println("Payment already received.");
            System.out.println("Handling shipping for paid order.");
            // 处理发货逻辑
            System.out.println("Order shipped.");
        } else if ("shipped".equalsIgnoreCase(status)) {
            System.out.println("Payment already received.");
            System.out.println("Order already shipped.");
        } else {
            System.out.println("Invalid order status: " + status);
        }
    }
}
  • 优化后代码
typescript 复制代码
// 状态接口
interface OrderState {
    void handlePayment();

    void handleShipping();
}

// 具体状态类
class PendingPaymentState implements OrderState {
    @Override
    public void handlePayment() {
        System.out.println("Payment handled for pending order.");
    }

    @Override
    public void handleShipping() {
        System.out.println("Cannot ship. Payment pending.");
    }
}

class PaidState implements OrderState {
    @Override
    public void handlePayment() {
        System.out.println("Payment already received.");
    }

    @Override
    public void handleShipping() {
        System.out.println("Shipping handled for paid order.");
    }
}

class ShippedState implements OrderState {
    @Override
    public void handlePayment() {
        System.out.println("Payment already received.");
    }

    @Override
    public void handleShipping() {
        System.out.println("Order already shipped.");
    }
}

// 上下文类
class Order {
    private OrderState currentState;

    public Order(OrderState initialState) {
        this.currentState = initialState;
    }

    public void handlePayment() {
        currentState.handlePayment();
    }

    public void handleShipping() {
        currentState.handleShipping();
    }

    public void setState(OrderState newState) {
        this.currentState = newState;
    }
}

public class StatePatternExample {
    public static void main(String[] args) {
        Order order = new Order(new PendingPaymentState());

        order.handlePayment();
        order.handleShipping();

        order.setState(new PaidState());

        order.handlePayment();
        order.handleShipping();

        order.setState(new ShippedState());

        order.handlePayment();
        order.handleShipping();
    }
}

5、枚举

对一些创建了枚举值,针对不同的枚举值有不同的操作时,枚举也可以消除if-else。个人感觉有点像策略模式或者表驱动。

  • 优化前
csharp 复制代码
enum OperateTypeEnum{  
    PO(1),  
    PR(2),  
    DC_INBOUND(3),  
    DC_OUTBOUND(4);  

    public final Integer code;  

    OperateTypeEnum(Integer code) {  
        this.code = code;  
    }  
}

private static Long getOperator(Integer operator){  
    if (OperateTypeEnum.PO.code.equals(operator)){  
        return getPoOperator();  
    } else if (OperateTypeEnum.PR.code.equals(operator)) {  
        return getPrOperator();  
    } else if (OperateTypeEnum.DC_INBOUND.code.equals(operator)) {  
        return getDcInboundOperator();  
    } else if (OperateTypeEnum.DC_OUTBOUND.code.equals(operator)) {  
        return getDcOutboundOperator();  
    }else {  
        return null;  
    }  
}

private static Long getPoOperator(){return 1L;}  

private static Long getPrOperator(){return 2L;}  

private static Long getDcInboundOperator(){return 3L;}  

private static Long getDcOutboundOperator(){return 4L;}  

private static Long getDwInboundOperator(){return 5L;}  

private static Long getDwOutboundOperator(){return 6L;}
  • 优化后的代码
typescript 复制代码
enum OperateTypeEnum{  
    PO(1){  
    @Override  
    protected Long getOperator() {  
            return 1L;  
        }  
    },  
    PR(2){  
    @Override  
    protected Long getOperator() {  
            return 2L;  
        }  
    },  
    DC_INBOUND(3){  
    @Override  
    protected Long getOperator() {  
            return 3L;  
        }  
    },  
    DC_OUTBOUND(4){  
    @Override  
    protected Long getOperator() {  
            return 4L;  
        }  
    };  

    public final Integer code;  

    OperateTypeEnum(Integer code) {  
        this.code = code;  
    }  

    public static OperateTypeEnum ofCode(Integer code){  
        return Arrays.stream(OperateTypeEnum.values())
        .filter(e -> e.code.equals(code))
        .findFirst().orElseThrow(() -> new RuntimeException("出错了"));  
    }  

    /**  
    * 定义一个公共方法  
    */  
    protected abstract Long getOperator();  
}

private static Long getOperator(Integer operatorType){  
    OperateTypeEnum operateTypeEnum = OperateTypeEnum.ofCode(operatorType);  
    return operateTypeEnum.getOperator();  
}

这种方式也是我再处理一些枚举时,对应不同的处理逻辑时常用的一种方式。比如根据订单类型的不同返回类型对应的数据。当然我们枚举方法中处理逻辑时如果想用bean的话,可以当做参数传入或者直接从Spring容器中获取。

6、表驱动(Map+函数方法)

表驱动编程是一种通过查找表格而不是嵌套条件语句来实现的编程方法。可以使用数据结构(如数组、Map)来存储条件和对应的操作,这样就不必用很多的逻辑语句(if 或 case)来把它们找出来的方法。

  • 优化前代码
csharp 复制代码
private static OrderInfoVO operateOrder(String orderType, OrderInfoDO orderInfo){  
    if (orderType.equals("PO")){  
        return handlePoOrder(orderInfo);  
    }else if (orderType.equals("INBOUND")){  
        return handleInboundOrder(orderInfo);  
    } else if (orderType.equals("OUTBOUND")) {  
        return handleOutboundOrder(orderInfo);  
    }  
}
  • 优化后代码
scss 复制代码
private static OrderInfoVO handlerOrder(String orderType, OrderInfoDO orderInfo){  
    Map<String, Function<OrderInfoDO, OrderInfoVO>> functionMap = Maps.newHashMap();  
    functionMap.put("PO", (orderInfo1) -> { return handlePoOrder(orderInfo1);});  
    functionMap.put("INBOUND", (orderInfo1) -> { return handleInboundOrder(orderInfo1);});  
    functionMap.put("OUTBOUND", (orderInfo1) -> { return handleOutboundOrder(orderInfo1);});  

    return functionMap.get(orderType).apply(orderInfo);  
}

当然Funtion也可以根据业务需要,可以为ConsumerPredicate等。

不过我们也可以利用Spring的依赖注入,将其转换为对应的Map。比如上述代码也可以这么优化:

typescript 复制代码
interface IOrderHandler{  
    /**  
    * 定义统一的处理接口  
    * @param orderInfo  
    * @return  
    */  
    OrderInfoVO handlerOrder(OrderInfoDO orderInfo);  
}  

@Component("PO")  
class PoOrderHandler implements IOrderHandler{  
    /**  
    * 处理Po  
    *  
    * @param orderInfo  
    * @return  
    */  
    @Override  
    public OrderInfoVO handlerOrder(OrderInfoDO orderInfo) {  
        return null;  
    }  
}  

@Component("INBOUND")  
class InboundOrderHandler implements IOrderHandler{  
    /**  
    * 处理Inbound  
    *  
    * @param orderInfo  
    * @return  
    */  
    @Override  
    public OrderInfoVO handlerOrder(OrderInfoDO orderInfo) {  
        // 具体处理逻辑  
        return null;  
    }  
}  

@Component("OUTBOUND")  
class InboundOrderHandler implements IOrderHandler{  
    /**  
    * 处理Outbound  
    *  
    * @param orderInfo  
    * @return  
    */  
    @Override  
    public OrderInfoVO handlerOrder(OrderInfoDO orderInfo) {  
        return null;  
    }  
}

public class OrderSerivceImpl implements IOrderService{

    @Autowired  
    private Map<String, IOrderHandler> orderHandlerMap;

    public OrderInfoVO handleOrderInfo(String orderType, OrderInfoDO orderInfo){
        IOrderHandler orderHandler = orderHandlerMap.get(orderType);  
        return orderHandler.handlerOrder(orderInfo);
    }
}

7、策略模式+工厂模式

我们可以使用策略模式将每个条件分支抽象为一个策略类,然后在主逻辑中使用策略类来执行相应的逻辑。这种方式可以降低代码的耦合性,使得代码更加可维护和可扩展。然后再使用工厂模式定义一个策略工厂类去管理这些策略,即对外提供的都是策略工厂的方法。这种方法可以有效的去除if-else,并且代码逻辑更容易阅读维护以及扩展。

比如上例中,我们在处理不同订单类型时的handler类就是一个个的策略,我们也可以创建一个策略工厂类。

arduino 复制代码
publid class OrderHandlerFactory{
    private static final Map<String, IOrderHandler> orderHandlerMap = Maps.newHashMap();  

static {  
    orderHandlerMap.put("PO", new PoOrderHandler());  
    orderHandlerMap.put("INBOUND", new InboundOrderHandler());  
    orderHandlerMap.put("OUTBOUND", new OutboundOrderHandler());  
}  

/**
* 获取具体处理的类
*/
public static IOrderHandler getOrderHandler(String orderType){  
    return orderHandlerMap.get(orderType);  
}
}

8、规则引擎

使用规则引擎来管理条件和对应的执行逻辑。例如,Drools 是一个强大的规则引擎,它允许你定义规则并动态执行它们。再比如LiteFlow,EasyRule,都可以通过管理条件和对应的执行逻辑。可以消除if-else。规则引擎适合处理复杂的业务逻辑。通过编排条件去处理业务逻辑。

总结:

上述方案都可以达到优化if-else的效果,但是采用那种方案还是要看具体的代码逻辑以及业务处理逻辑,重要的是要评估项目的复杂性、维护性和性能需求,选择最适合项目需求的优化方案。在实际开发中,通常会根据具体情况结合多种方式来达到更好的优化效果。

相关推荐
海绵波波1072 小时前
flask后端开发(10):问答平台项目结构搭建
后端·python·flask
网络风云4 小时前
【魅力golang】之-反射
开发语言·后端·golang
Q_19284999064 小时前
基于Spring Boot的电影售票系统
java·spring boot·后端
运维&陈同学5 小时前
【Kibana01】企业级日志分析系统ELK之Kibana的安装与介绍
运维·后端·elk·elasticsearch·云原生·自动化·kibana·日志收集
Javatutouhouduan7 小时前
如何系统全面地自学Java语言?
java·后端·程序员·编程·架构师·自学·java八股文
后端转全栈_小伵8 小时前
MySQL外键类型与应用场景总结:优缺点一目了然
数据库·后端·sql·mysql·学习方法
编码浪子8 小时前
Springboot高并发乐观锁
后端·restful
uccs8 小时前
go 第三方库源码解读---go-errorlint
后端·go
Mr.朱鹏9 小时前
操作002:HelloWorld
java·后端·spring·rabbitmq·maven·intellij-idea·java-rabbitmq
编程洪同学10 小时前
Spring Boot 中实现自定义注解记录接口日志功能
android·java·spring boot·后端