if-else-if 优化办法

550 阅读2分钟

    Hello!小伙伴们,你们的业务代码中是否经常遇到这样的代码,是不是惨不忍睹

下面看一下实际的场景

获取验机接口接口,验机项有几十项

外观字段:清洁程度、警示灯、轮胎、栏杆锁销、篮筐
功能字段:叉车:刹车释放功能、平台延伸功能、急停开关、刹车、升降动作;臂车:各部位润滑、急停开关、刹车、升降动作、发动机

    /**
     * 获取外观验机结果
     *
     * @param check 验机结果
     * @param res   返回值
     */
    private void getFacadeCheckResult(CheckPo check, QueryDeviceCheckResponse res) {
        res.setFacade(DeviceEnum.CheckItemResult.NORMAL.getState());
        if (check.getCleanLevelIsNorm() == 0) {
            res.setFacade(0);
        } else if (check.getWarnLightIsNorm() == 0) {
            res.setFacade(0);
        } else if (check.getTireIsNorm() == 0) {
            res.setFacade(0);
        } else if (check.getRailingLockingPinIsNorm() == 0) {
            res.setFacade(0);
        } else if (check.getBasketOutIsShape() == 0) {
            res.setFacade(0);
        }
    }

    /**
     * 获取功能验机结果
     *
     * @param check 验机结果
     * @param res   返回值
     */
    private void getForkFunctionCheckResult(CheckPo check, QueryDeviceCheckResponse res) {
        res.setFunction(DeviceEnum.CheckItemResult.NORMAL.getState());
        if (DeviceEnum.DeviceType.FORK.name().equalsIgnoreCase(res.getDeviceType())) {
            if (check.getBrakeReleaseIsNorm() == DeviceEnum.CheckItemResult.ABNORMAL.getState()) {
                res.setFunction(DeviceEnum.CheckItemResult.ABNORMAL.getState());
            } else if (check.getPlatformExtensionIsNorm() == DeviceEnum.CheckItemResult.ABNORMAL.getState()) {
                res.setFunction(DeviceEnum.CheckItemResult.ABNORMAL.getState());
            } else if (check.getEmergencySwitchIsNorm() == DeviceEnum.CheckItemResult.ABNORMAL.getState()) {
                res.setFunction(DeviceEnum.CheckItemResult.ABNORMAL.getState());
            } else if (check.getBrakeIsNorm() == DeviceEnum.CheckItemResult.ABNORMAL.getState()) {
                res.setFunction(DeviceEnum.CheckItemResult.ABNORMAL.getState());
            } else if (check.getLiftingIsNorm() == DeviceEnum.CheckItemResult.ABNORMAL.getState()) {
                res.setFunction(DeviceEnum.CheckItemResult.ABNORMAL.getState());
            }
        }
        if (getCheckItemResult(check, FORK_FUNCTION_CHECK_FIELD)) {
            res.setFacade(DeviceEnum.CheckItemResult.ABNORMAL.getState());
        }
    }

    /**
     * 获取外功能机结果
     *
     * @param check 验机结果
     * @param res   返回值
     */
    private void getArmOrCurvedFunctionCheckResult(CheckPo check, QueryDeviceCheckResponse res) {
        res.setFunction(DeviceEnum.CheckItemResult.NORMAL.getState());
        if (DeviceEnum.DeviceType.ARM.name().equalsIgnoreCase(res.getDeviceType())
                || DeviceEnum.DeviceType.CURVED.name().equalsIgnoreCase(res.getDeviceType())) {
            if (check.getLubricationPartsIsNorm() == 0) {
                res.setFunction(1);
            }
            else if (check.getEmergencySwitchIsNorm() == 0) {
                res.setFunction(1);
            }
            else if (check.getBrakeIsNorm() == 0) {
                res.setFunction(1);
            }
            else if (check.getLiftingIsNorm() == 0) {
                res.setFunction(1);
            }
            if (check.getIsEngine() == 1) {
                if (check.getCoolantIsNorm() == 0) {
                    res.setFunction(0);
                } else if (check.getOilLevelIsNorm() == 0) {
                    res.setFunction(0);
                } else if (check.getAirFilterIsNorm() == 0) {
                    res.setFunction(0);
                } else if (check.getEngineBeltIsNorm() == 0) {
                    res.setFunction(0);
                } else if (check.getEngineOilPortIsNorm() == 0) {
                    res.setFunction(0);
                } else if (check.getWaterSeparatorIsNorm() == 0) {
                    res.setFunction(0);
                }
            }
        }
    }

通过反射优化后
/**
 * 外观字段:清洁程度、警示灯、轮胎、栏杆锁销、篮筐
 */
private static final List<String> FACADE_CHECK_FIELD = new ArrayList<>();

static {
	FACADE_CHECK_FIELD.add("cleanLevelIsNorm");
	FACADE_CHECK_FIELD.add("warnLightIsNorm");
	FACADE_CHECK_FIELD.add("tireIsNorm");
	FACADE_CHECK_FIELD.add("railingLockingPinIsNorm");
	FACADE_CHECK_FIELD.add("basketOutIsShape");
}

/**
 * 功能字段:叉车:刹车释放功能、平台延伸功能、急停开关、刹车、升降动作;
 */
private static final List<String> FORK_FUNCTION_CHECK_FIELD = new ArrayList<>();

static {
	FORK_FUNCTION_CHECK_FIELD.add("brakeReleaseIsNorm");
	FORK_FUNCTION_CHECK_FIELD.add("platformExtensionIsNorm");
	FORK_FUNCTION_CHECK_FIELD.add("emergencySwitchIsNorm");
	FORK_FUNCTION_CHECK_FIELD.add("brakeIsNorm");
	FORK_FUNCTION_CHECK_FIELD.add("liftingIsNorm");
}

/**
 * 功能字段:臂车:各部位润滑、急停开关、刹车、升降动作、发动机
 */
private static final List<String> ARM_OR_CURVED_FUNCTION_CHECK_FIELD = new ArrayList<>();

static {
	ARM_OR_CURVED_FUNCTION_CHECK_FIELD.add("lubricationPartsIsNorm");
	ARM_OR_CURVED_FUNCTION_CHECK_FIELD.add("emergencySwitchIsNorm");
	ARM_OR_CURVED_FUNCTION_CHECK_FIELD.add("brakeIsNorm");
	ARM_OR_CURVED_FUNCTION_CHECK_FIELD.add("liftingIsNorm");
	ARM_OR_CURVED_FUNCTION_CHECK_FIELD.add("coolantIsNorm");
	ARM_OR_CURVED_FUNCTION_CHECK_FIELD.add("oilLevelIsNorm");
	ARM_OR_CURVED_FUNCTION_CHECK_FIELD.add("airFilterIsNorm");
	ARM_OR_CURVED_FUNCTION_CHECK_FIELD.add("engineBeltIsNorm");
	ARM_OR_CURVED_FUNCTION_CHECK_FIELD.add("engineOilPortIsNorm");
	ARM_OR_CURVED_FUNCTION_CHECK_FIELD.add("waterSeparatorIsNorm");
}

/**
 * 获取验机项结果
 *
 * @param check      验机结果
 * @param fieldNames 检查项字段集合
 */
private boolean getCheckItemResult(CheckPo check, List<String> fieldNames) {
	Field[] fields = CheckPo.class.getDeclaredFields();
	for (Field f : fields) {
		try {
			for (String fieldName : fieldNames) {
				if (f.getName().equals(fieldName)) {
					f.setAccessible(true);
					if (f.get(check) instanceof Integer) {
						Integer result = (Integer) f.get(check);
						// 有异常
						if (result == 0) {
							return true;
						}
					}
				}
			}
		} catch (IllegalAccessException e) {
			log.error("getCheckItemResult exception ", e);
		}
	}
	return false;
}

代码有以下几个问题

1、代码不整洁,可读性差

2、代码不容易维护

3、代码扫描不过,圈复杂度太高

今天我想来总结一下这样的if-else-if 怎样优化

其实最先想到的就是封装+卫语句

封装就是把if中分散的凌乱的代码封装成一个方法,卫语句就是把复杂的的条件表达式拆分成多个条件表达式,条件为真时立刻从方法体中返回。优化后代码大概张这个样子

 if(condition) { 
    doSth1();   
    return;
 }
 if(condition) {
    doSth2();    
    return;
 }  
 if(condition) {
     doSth3();    
     return;
 }
  、、
  return;

    有点Java思想的人的就会利用多态了,你也可以说是工厂模式或者策略模式等,本质上都是多态的运用,优化后的代码长大概张这个样子

private TravelStrategy strategy;

public TravelStrategy travel (String type){
	if ("TRAIN".equals(type)){
	    strategy = new StrategyTrain();
	} else if ("BUS".equals(type)){
	    strategy = new StrategyBus();
	} else if ("HIGHTRAIN".equals(type)){
            strategy = new StrategyHighTrain();
        } else if ("CAR".equals(type)){
            strategy = new StrategyCar();
        } else if ("METRO".equals(type)){
            strategy = new StrategyMetro();
        }
        、、省略其他方式
	return Strategy;
}            

    代码的实现逻辑下沉到子类中去完成,代码清爽,逻辑清晰。但是如果实现的子类有几十个怎么办呢?就像中国有34个 省份难道要写34个if(这个是我实际工作中遇见的场景)进一步优化,我们可以把初始化的动作放在Map里当然也可以利用数组,在类加载的时候就把需要 的对象初始化好

public TravelStrategy travel (String type){
        
	TravelStrategy strategy = map.get(type);
}

最后代码是这个样子的,其实这是内存用空间换来的,牺牲掉了一部分内存空间换来了干掉了几十个if, 那么有没有其他的写法呢?其实我们还可以用枚举,枚举也是可以有构造函数

public enum TravelEnum {
    
    TRAIN("TRAIN",new StrategyTrain()),

    BUS("BUS",new StrategyBus());

    private TravelStrategy strategy;

    // 构造方法里传入对象实例
    PayEnum(String name,TravelStrategy strategy) {    
        this.name = name;    
        this.strategy = strategy;
    }

    public Strategy getStrategy() {
        return strategy;
    }

    public void setStrategy(TravelStrategy strategy) {       
         this.strategy = strategy;
    }
    
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    /**     
     * 根据名称获取策略(这里避免了写过多的if-else-if/case-when)
     * @param name
     * @return
     */
    public static TravelStrategy getStrategy(String name) {        
        for(TravelEnum travel : TravelEnum.values()) {            
            if (travel.name.equals(name)) {
                return travel.strategy;
            }
        }
        return null;
    }
}

    总结:

/**
 * if-else-if 优化办法
 *
 * 1、多态+map
 * 2、多态+枚举
 * 3、多态+数组
 * 4、使用卫语句,将复杂的条件表达式拆分成多个条件表达式
 * 5、反射
 * 6、Spring注入一个集合
 * @Autowired
 * List<Strategy> strategyList Strategy子类有一个标识字段 */

关于策略模式可以参考:juejin.cn/post/694431…

你有什么好的实现方式或者建议欢迎留言