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


    引言

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

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

    1. switch

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

    原语句

    1. class="prettyprint hljs cs" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", 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)  { 
    2. if(status == 1){
    3. System.out.println("订单未接单");
    4. }else if(status == 2){
    5. System.out.println("订单未发货");
    6. }else if(status == 3){
    7. System.out.println("订单未签收");
    8. }else{
    9. System.out.println("订单已签收");
    10. }
    11. }

    switch

    1. class="prettyprint hljs cs" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", 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)  { 
    2. switch (status){
    3. case 1:
    4. System.out.println("订单未接单");
    5. break;
    6. case 2:
    7. System.out.println("订单未发货");
    8. break;
    9. case 3:
    10. System.out.println("订单未签收");
    11. break;
    12. default:
    13. System.out.println("订单已签收");
    14. }
    15. }

    总结:

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

    2. 函数式接口

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

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

    1. class="prettyprint hljs kotlin" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", 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
    2. public class FunctionInterfaceStrategy {
    3. /**
    4. * key 方法参数,多个参数可以自定义一个实体类处理
    5. * value 方法返回值
    6. */
    7. private Map<Integer, Function<Object,Boolean>> operationMap;
    8. @PostConstruct
    9. private void init(){
    10. operationMap = new HashMap<>();
    11. operationMap.put(1,this::takeOrder);
    12. operationMap.put(2,this::sendOrder);
    13. operationMap.put(3,this::signOrder);
    14. operationMap.put(4,this::finishOrder);
    15. }
    16. public Boolean doOperation(Object params,Integer status){
    17. return operationMap.get(status) == null || operationMap.get(status).apply(params);
    18. }
    19. private Boolean takeOrder(Object params){
    20. // TODO 比较复杂的处理逻辑
    21. System.out.println("订单未接单");
    22. return true;
    23. }
    24. private Boolean sendOrder(Object params){
    25. // TODO 比较复杂的处理逻辑
    26. System.out.println("订单未发货");
    27. return true;
    28. }
    29. private Boolean signOrder(Object params){
    30. // TODO 比较复杂的处理逻辑
    31. System.out.println("订单未签收");
    32. return true;
    33. }
    34. private Boolean finishOrder(Object params){
    35. // TODO 比较复杂的处理逻辑
    36. System.out.println("订单已签收");
    37. return true;
    38. }
    39. }

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

    1. class="prettyprint hljs less" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", 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
    2. private FunctionInterfaceStrategy functionInterfaceStrategy;
    3. functionInterfaceStrategy.doOperation("参数",1);

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

    3. 策略模式

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

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

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

    1. class="prettyprint hljs php" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", 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  { 
    2. /**
    3. * 获取实现类标识
    4. * @return
    5. */
    6. Integer getType();
    7. /**
    8. * 逻辑处理
    9. * @param params
    10. * @return
    11. */
    12. Boolean handler(Object params);
    13. }

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

    1. class="prettyprint hljs kotlin" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", 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
    2. public class SendOrderStrategy implements OrderStrategy{
    3. @Override
    4. public Integer getType() {
    5. return 2;
    6. }
    7. @Override
    8. public Boolean handler(Object params) {
    9. // TODO 复杂的处理逻辑
    10. System.out.println("订单未发货");
    11. return true;
    12. }
    13. }
    14. @Service
    15. public class SignOrderStrategy implements OrderStrategy{
    16. @Override
    17. public Integer getType() {
    18. return 3;
    19. }
    20. @Override
    21. public Boolean handler(Object params) {
    22. // TODO 复杂的处理逻辑
    23. System.out.println("订单未签收");
    24. return true;
    25. }
    26. }
    27. @Service
    28. public class TakeOrderStrategy implements OrderStrategy{
    29. @Override
    30. public Integer getType() {
    31. return 1;
    32. }
    33. @Override
    34. public Boolean handler(Object params) {
    35. // TODO 复杂的处理逻辑
    36. System.out.println("订单未接单");
    37. return true;
    38. }
    39. }

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

    1. class="prettyprint hljs java" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", 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
    2. @AllArgsConstructor
    3. public class OrderStrategyFactory {
    4. private final List<OrderStrategy> orderStrategyList;
    5. private static Map<Integer,OrderStrategy> strategyMap = new HashMap<>();
    6. @PostConstruct
    7. private void init(){
    8. for (OrderStrategy orderStrategy : orderStrategyList) {
    9. strategyMap.put(orderStrategy.getType(),orderStrategy);
    10. }
    11. }
    12. /**
    13. * 执行方法
    14. * @param status
    15. * @param params
    16. * @return
    17. */
    18. public Boolean handler(Integer status,Object params){
    19. return strategyMap.get(status).handler(params);
    20. }
    21. }

    4、方法调用

    1. class="prettyprint hljs less" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", 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
    2. @RequestMapping("ifelse")
    3. @AllArgsConstructor
    4. public class IfElseController {
    5. private final OrderStrategyFactory orderStrategyFactory;
    6. @GetMapping("strategy")
    7. public Boolean strategy(Integer status){
    8. return orderStrategyFactory.handler(status,"1");
    9. }
    10. }

    总结:

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

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

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

    4. 卫语句

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

    原语句

    1. class="prettyprint hljs cs" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", 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)  { 
    2. if(status != null) {
    3. if(status != 0){
    4. if(status == 1){
    5. System.out.println("订单未接单");
    6. }
    7. }
    8. }
    9. }<

    卫语句

    1. class="prettyprint hljs kotlin" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", 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) { 
    2. if(status == null){
    3. return;
    4. }
    5. if(status != 0){
    6. return;
    7. }
    8. if(status == 1){
    9. System.out.println("订单未接单");
    10. }
    11. }

     

  • 相关阅读:
    为何每个开发者都在谈论Go?
    idea2023.2.3版本出现reading maven projects的进度条一直卡住的问题
    SQL报了一个不常见的错误,让新来的实习生懵了
    【MySql】数据库的聚合查询
    一分钟带你了解智能遥测终端机RTU
    Java中使用MyBatis框架连接和操作MySQL数据库
    java学习第三天笔记-运算符01算术运算符的基本用法41
    系统架构常用的工具
    bmp图片处理
    【Vue 基础知识】控制元素显示隐藏的方法和区别
  • 原文地址:https://blog.csdn.net/Java_ttcd/article/details/126384433