如何优雅地书写if-else(策略模式、函数式接口、卫语句)

引言

在日常开发中我们常常遇到有多个if else的情况,之间书写显得代码冗余难看,对于追求更高质量代码的同学,就会思考如何优雅地处理这种代码

下面我们来探讨下几种优化if else的方法

1. switch

switch方法针对枚举值处理有不错的效果,比如针对不同的订单状态时要做不同的处理,因为状态值有限,这时我们就可以直接使用switch来针对不同状态做不同的处理:

原语句

<pre class="prettyprint hljs cs" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">public  void  before(Integer status)  { 
        if(status == 1){ 
            System.out.println("订单未接单");
        }else  if(status ==  2){ 
            System.out.println("订单未发货");
        }else  if(status ==  3){ 
            System.out.println("订单未签收");
        }else{ 
            System.out.println("订单已签收");
        }
    }

switch

<pre class="prettyprint hljs cs" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">public  void  greater(Integer status)  { 
        switch (status){ 
            case 1:
                System.out.println("订单未接单");
                break;
            case 2:
                System.out.println("订单未发货");
                break;
            case 3:
                System.out.println("订单未签收");
                break;
            default:
                System.out.println("订单已签收");
        }
    }

总结:

switch语句适用于判断条件有限且不需要经过复杂的计算,处理语句简单的场景。如果我们的判断条件需要经过一系列复杂的计算才能得到,或者处理语句逻辑也比较复杂时,我们就要考虑其他的处理方式了,毕竟在case中书写一大堆处理语句并不算得让人舒适的事情

2. 函数式接口

针对比较复杂的处理逻辑时,我们偏向于将这些处理逻辑单独抽离出来,而不是还放在一个方法里处理,增加整体的可读性和解耦性,也是我们衍生出利用函数式接口来处理if else的模式

函数式接口map处理if else的要义,是将各个条件的复杂处理逻辑单独抽取为一个函数式接口方法,通过统一的判断条件来调用不同的方法,具体示例如下

<pre class="prettyprint hljs kotlin" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">@Component
public class  FunctionInterfaceStrategy  { 

    /**
     * key 方法参数,多个参数可以自定义一个实体类处理
     * value 方法返回值
     */
    private Map<Integer, Function<Object,Boolean>> operationMap;

    @PostConstruct
    private void init(){ 
        operationMap = new HashMap<>();
        operationMap.put(1,this::takeOrder);
        operationMap.put(2,this::sendOrder);
        operationMap.put(3,this::signOrder);
        operationMap.put(4,this::finishOrder);
    }

    public Boolean doOperation(Object params,Integer status){ 
        return operationMap.get(status) == null || operationMap.get(status).apply(params);
    }

    private Boolean takeOrder(Object params){ 
        // TODO 比较复杂的处理逻辑
        System.out.println("订单未接单");
        return true;
    }

    private Boolean sendOrder(Object params){ 
        // TODO 比较复杂的处理逻辑
        System.out.println("订单未发货");
        return true;
    }

    private Boolean signOrder(Object params){ 
        // TODO 比较复杂的处理逻辑
        System.out.println("订单未签收");
        return true;
    }

    private Boolean finishOrder(Object params){ 
        // TODO 比较复杂的处理逻辑
        System.out.println("订单已签收");
        return true;
    }

}

调用时就不用再用if else区分了,直接传入参数到function map中调用

<pre class="prettyprint hljs less" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">@Autowired
    private FunctionInterfaceStrategy functionInterfaceStrategy;

    functionInterfaceStrategy.doOperation("参数",1);

当然我们上述演示的是有参数有返回值的函数式接口,实际生产中我们可能还需要其他形式的函数式接口,我们将其单独罗列出来,供大家参考使用

3. 策略模式

上述的函数式接口的形式,实际上是针对方法进行了分离,所有的实现方法还是放在了一个类里,即使你可以在 FunctionInterfaceStrategy 类中通过依赖注入的形式再次调用其他类的方法,但是这样的模式,已经趋近于我们要将的下一种方法,即使用策略模式来解决 if else

策略模式的形式适用于实现方法更加复杂的情况,需要将处理逻辑解耦的更加干净的场景

1、首先我们需要创建一个接口类,用来规定我们后续的实现类的格式

<pre class="prettyprint hljs php" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">public interface  OrderStrategy  { 

    /**
     * 获取实现类标识
     * @return
     */
    Integer getType();

    /**
     * 逻辑处理
     * @param params
     * @return
     */
    Boolean handler(Object params);

}

2、其次针对每个判断条件创建一个实现类

<pre class="prettyprint hljs kotlin" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">@Service
public class  SendOrderStrategy  implements  OrderStrategy{ 

    @Override
    public Integer getType() { 
        return 2;
    }

    @Override
    public Boolean handler(Object params) { 
        // TODO 复杂的处理逻辑
        System.out.println("订单未发货");
        return true;
    }
}

@Service
public class  SignOrderStrategy  implements  OrderStrategy{ 

    @Override
    public Integer getType() { 
        return 3;
    }

    @Override
    public Boolean handler(Object params) { 
        // TODO 复杂的处理逻辑
        System.out.println("订单未签收");
        return true;
    }
}

@Service
public class  TakeOrderStrategy  implements  OrderStrategy{ 

    @Override
    public Integer getType() { 
        return 1;
    }

    @Override
    public Boolean handler(Object params) { 
        // TODO 复杂的处理逻辑
        System.out.println("订单未接单");
        return true;
    }
}

3、创建一个策略工厂类,承装实现类

<pre class="prettyprint hljs java" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">@Component
@AllArgsConstructor
public class  OrderStrategyFactory  { 

    private final List<OrderStrategy> orderStrategyList;

    private static Map<Integer,OrderStrategy> strategyMap = new HashMap<>();

    @PostConstruct
    private  void  init(){ 
        for (OrderStrategy orderStrategy : orderStrategyList) { 
            strategyMap.put(orderStrategy.getType(),orderStrategy);
        }
    }

    /**
     * 执行方法
     * @param status
     * @param params
     * @return
     */
    public  Boolean  handler(Integer status,Object params){ 
        return strategyMap.get(status).handler(params);
    }

}

4、方法调用

<pre class="prettyprint hljs less" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">@RestController
@RequestMapping("ifelse")
@AllArgsConstructor
public class IfElseController { 

    private final OrderStrategyFactory orderStrategyFactory;

    @GetMapping("strategy")
    public Boolean strategy(Integer status){ 
        return orderStrategyFactory.handler(status,"1");
    }

}

总结:

通过上述的代码示例,大家其实可以发现,函数式接口和策略模式有异曲同工之处,根本区别在于是否需要将实现方法单独抽取为一个实现类。抽取的粒度越细也就说明解耦越强

使用策略模式,后续如果需要增加if else条件的话,只需要增加实现类即可,针对后续的处理更加方便

最终使用哪一个还需要根据具体的业务情况而定

4. 卫语句

我们经常需要在方法前处理各种参数嵌套判断逻辑,如果不满足条件就直接返回了,这种情况更加推荐使用卫语句来处理

原语句

<pre class="prettyprint hljs cs" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">public  void  before(Integer status)  { 
        if(status != null) { 
            if(status != 0){ 
                if(status == 1){ 
                    System.out.println("订单未接单");
                }
            }
        }
    }<

卫语句

<pre class="prettyprint hljs kotlin" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">public void greater(Integer status) { 
        if(status == null){ 
            return;
        }
        if(status != 0){ 
            return;
        }
        if(status == 1){ 
            System.out.println("订单未接单");
        }
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值