如果代码中存在大量的 if-else 结构,不仅可读性降低,后期维护也很麻烦。在实际开发中,需要根据代码的复杂度、可读性和可扩展性,来确定最佳的优化方案。总之,适合自己的才是最好的。
常见的 if-else 结构大致可以分为两种,顺序型和嵌套型,下文会根据实际场景进行分析,并提供针对性的优化思路。
1. 顺序结构优化
public void process(String x) {
if ("A".equals(x)){
/* 具体操作 A */
}
else if ("B".equals(x)){
/* 具体操作 B */
}
else if ("C".equals(x)){
/* 具体操作 C */
}
}
场景分析:
- 基于单一变量的条件判断。
- 各分支条件没有依赖关系。
- 各分支下执行逻辑相对独立。
1.1. 单 if 结构
public void process(String x) {
if ("A".equals(x)){
/* 具体操作 A */
}
if ("B".equals(x)){
/* 具体操作 B */
}
if ("C".equals(x)){
/* 具体操作 C */
}
}
优缺点:
- 减少了 else 关键字,直观感受更简洁。
- 由于条件互斥且只会满足其中一个,单 if 会造成多余的判断。比如 x 等于 A,在处理完分支 A 后,仍会继续判断是否等于 B 和 C。
实践建议:
如果条件互斥且判断次数较多,if-else 更有效率;
如果追求代码可读性,单 if 结构更简洁。
1.2. switch 模式
public void process(String x) {
switch (x) {
case "A":
/* 具体操作 A */
break;
case "B":
/* 具体操作 B */
break;
case "C":
/* 具体操作 C */
break;
default: break;
}
}
优缺点:
- switch 结构清晰且高效,代码可维护性好。
- 适合匹配值为常量或枚举类型。
- 只能处理等值判断,复杂条件判断无法实现,如大于、小于。
实践建议:
适合等值判断,且匹配值为常量或枚举类型的特定场景。
1.3. Map+函数式编程(表驱动)
public static final Map<String, Function<String,String>> actionMap = new ConcurrentHashMap<>();
// 规则
public static final Function<String,String> actionA = param -> {return "A";};
public static final Function<String,String> actionB = param -> {return "B";};
public static final Function<String,String> actionC = param -> {return "C";};
// 初始化规则到 actionMap
static {
actionMap.put("A", actionA);
actionMap.put("B", actionB);
actionMap.put("C", actionC);
}
public void process4(String x,String param ) {
actionMap.get(x).apply(param);
}
优缺点:
- 表驱动模式将判断条件和处理逻辑解耦,通过 Map 表来组织规则,可以动态扩展和修改。
- 要求 JDK 版本 1.8 以上,且函数式编程带来一定的复杂度,可读性变差。
- 只能处理等值判断,复杂条件判断无法实现,如大于、小于。
实践建议:
适合规则较多、变动频繁的场景,如把 actionMap 的初始化独立出来,可以根据外部配置文件动态加载处理规则。
1.4. 工厂+策略模式
// 策略接口
public interface Strategy {
void execute(String param);
}
// 策略实现 A
public class StrategyA implements Strategy {
public void execute(String param) { /* 具体操作 A */ }
}
// 策略实现 B
public class StrategyB implements Strategy {
public void execute(String param) { /* 具体操作 B */ }
}
// 策略实现 C
public class StrategyC implements Strategy {
public void execute(String param) { /* 具体操作 C */ }
}
// 策略类型
public enum StrategyType {
A,B,C;
}
// 策略工厂
public class StrategyFactory {
private static final Map<StrategyType, Strategy> strategyMap = new ConcurrentHashMap<>();
{
strategyMap.put(StrategyType.A,new StrategyA());
strategyMap.put(StrategyType.B,new StrategyB());
strategyMap.put(StrategyType.C,new StrategyC());
}
public static Strategy getStrategy(StrategyType type) {
return strategyMap.get(type);
}
}
// 调用
StrategyFactory.getStrategy(StrategyType.A).execute(param);
优缺点:
- 每个策略可以独立实现,符合开放封闭原则,降低代码耦合度。
- 利用策略接口约束行为,有利于功能扩展方便,比如在接口新增一个 submit(String param)方法,子类分别实现就行了。
- 需要定义策略接口及其实现类,会增加文件数量,可能会增加系统复杂度。
实践建议:
适合复杂逻辑,扩展性高,尤其是需要动态选择不同行为的场景。如根据不同的会员类型来处理对应付费权益。
可结合依赖注入框架(如 Spring)来管理策略的实例化和调用。
2. 嵌套结构优化
// 嵌套 if-else 结构
public void process(String X, String Y, String Z) {
if ("A".equals(X)) {
if ("B".equals(Y)) {
if ("C".equals(Z)) {
/* 具体操作 A && B && C*/
} else {
/* 具体操作 !C */
}
} else {
/* 具体操作 !B */
}
} else {
/* 具体操作 !A */
}
}
2.1. 卫语句
public void process(String X, String Y, String Z) {
// 反向处理逻辑
if(!"A".equals(X)){
/* 具体操作 !A */
return;
}
if(!"B".equals(Y)){
/* 具体操作 !B */
return;
}
if(!"C".equals(Z)){
/* 具体操作 !C */
return;
}
// 正向处理逻辑
/* 具体操作 A && B && C*/
}
优缺点:
- 卫语句通过预先检查关键条件,在顶部排除不符合的条件,把多个嵌套 if-else 转为单 if 结构。
- 可能会在不同的条件分支中,多次使用 return 语句,增加控制流程的复杂性。
实践建议:
适合条件检查较多,且需要处理反向逻辑的特定场景。
2.2. 责任连模式
// 抽象处理器接口
public abstract class Processor {
protected Processor nextProcessor;
public Processor setNext(Processor nextProcessor) {
this.nextProcessor = nextProcessor;
return nextProcessor;
}
public abstract void process(String X, String Y, String Z);
}
// 具体处理器实现
public class AProcessor extends Processor {
@Override
public void process(String X, String Y, String Z) {
if ("A".equals(X)) {
if (nextProcessor != null) {
nextProcessor.process(X, Y, Z);
}
} else {
/* 具体操作 !A */
}
}
}
public class BProcessor extends Processor {
@Override
public void process(String X, String Y, String Z) {
if ("B".equals(Y)) {
if (nextProcessor != null) {
nextProcessor.process(X, Y, Z);
}
} else {
/* 具体操作 !B */
}
}
}
public class CProcessor extends Processor {
@Override
public void process(String X, String Y, String Z) {
if ("C".equals(Z)) {
/* 具体操作 A && B && C*/
} else {
/* 具体操作 !C */
}
}
}
// 构建责任链
Processor chain = new AProcessor();
chain.setNext(new BProcessor()).setNext(new CProcessor());
chain.process("X", "Y", "Z");
优缺点:
- 每个判断逻辑独立成一个处理类,降低耦合度。
- 每个条件都需要一个处理类,可能会导致文件数量增加,复杂的责任链容易引入调试困难。
- 可以根据需要,动态调整处理器的顺序和内容,易扩展。
实践建议:
适合按条件顺序执行的特定场景,请求按链式传递,直到找到符合条件的节点来处理。
3. 总结
- 简单判断条件:使用 if-else 或单 if 更直接。
- 枚举或常量判断:switch 结构更简洁。
- 规则变动频繁或需要动态选择行为:表驱动(Map + 函数式编程)或策略模式更灵活。
- 按顺序判断处理:责任链模式更适合。