最恶心的 if-else 示例
如果抛弃业务逻辑,看下面这样一段代码,已经足够恶心了。这还是消除了业务逻辑后的简化版,如果加上真实业务,可读性将更差:
if condition1:
if sub_condition1:
if sub_sub_condition1:
if sub_sub_sub_condition1:
do_extreme_thing1()
elif sub_sub_sub_condition2:
do_extreme_thing2()
else:
do_extreme_thing3()
elif sub_sub_condition2:
if sub_sub_sub_condition3:
do_extreme_thing4()
else:
do_extreme_thing5()
else:
do_extreme_thing6()
elif sub_condition2:
if sub_sub_condition3:
if sub_sub_sub_condition4:
do_extreme_thing7()
else:
do_extreme_thing8()
else:
do_extreme_thing9()
else:
do_something_else1()
elif condition2:
if sub_condition3:
if sub_sub_condition4:
if sub_sub_sub_condition5:
do_extreme_thing10()
else:
do_extreme_thing11()
else:
do_extreme_thing12()
else:
do_something_else2()
else:
if sub_condition4:
if sub_sub_condition5:
if sub_sub_sub_condition6:
do_extreme_thing13()
else:
do_extreme_thing14()
else:
do_extreme_thing15()
else:
handle_default()
之前的代码运行还算可以,一直没出什么错误,说明在某个阶段是合格的。但后来需要改进、增加功能,拿到手后直接头大。
一些技巧
能用 if 就不用 if-else
看下面这段代码:
public void performOperation(int input) {
if (input > 5) {
// do something
} else {
// do something else
}
}
提前 return 后:
public void performOperation(int input) {
if (input > 5) {
// do something
return;
}
// do something else
}
这里的关键动作是”卫语句(Guard Clause)“:当满足特定条件时立刻结束当前方法,让主干逻辑保持在最外层缩进。
它带来的好处:
- 降层级——原本 if-else 里
else那段代码要缩进 1 级,现在回到方法顶层 - 改突出——
if里那段其实是”提前退出的异常/边缘 case”,提前 return 让读者看到”下面才是核心逻辑” - 易扩展——将来再来一个前置校验,继续在开头加一段
if (...) return;即可,不用改动主逻辑的缩进
嵌套 3 层以上的 if-else,几乎总能用卫语句先拉平至少一层。
使用策略模式
假设我们要对不同类型的文件做不同处理。最朴素的写法:
public String processFile(File file, String fileType) {
if ("json".equals(fileType)) {
// 处理 JSON
return handleJson(file);
} else if ("xml".equals(fileType)) {
// 处理 XML
return handleXml(file);
}
return null;
}
当前的写法可读性还可以,但保不齐后续会新增其他类型——txt、yaml、csv……如果新增这些功能,最简单的情形就是继续增加 if-else 分支。但这违反了开闭原则,并且维护性、可读性、整洁性都会下降。
改用策略模式:
步骤 1:定义抽象策略接口
public interface FileStrategy {
String doOperation(File file);
}
步骤 2:定义各种具体策略
public class JsonFileStrategy implements FileStrategy {
@Override
public String doOperation(File file) {
// ... 处理 JSON
return "...";
}
}
public class XmlFileStrategy implements FileStrategy {
@Override
public String doOperation(File file) {
// ... 处理 XML
return "...";
}
}
public class TxtFileStrategy implements FileStrategy {
@Override
public String doOperation(File file) {
// ... 处理 TXT
return "...";
}
}
步骤 3:上下文对象负责调度
class FileContext {
private final FileStrategy strategy;
public FileContext(FileStrategy strategy) {
this.strategy = strategy;
}
public String executeStrategy(File file) {
return strategy.doOperation(file);
}
}
步骤 4:用工厂 + Map 做类型到策略的映射
public class StrategyFactory {
private static final StrategyFactory INSTANCE = new StrategyFactory();
private static final Map<String, FileStrategy> strategyMap = new HashMap<>();
static {
strategyMap.put("txt", new TxtFileStrategy());
strategyMap.put("xml", new XmlFileStrategy());
strategyMap.put("json", new JsonFileStrategy());
}
private StrategyFactory() {}
public FileStrategy create(String fileType) {
return strategyMap.get(fileType);
}
public static StrategyFactory getInstance() {
return INSTANCE;
}
}
调用侧变成:
FileStrategy strategy = StrategyFactory.getInstance().create(fileType);
String result = new FileContext(strategy).executeStrategy(file);
代价与收益:
- ❌ 代码量增加,需要多写几个类
- ❌ 认知门槛提高:读者要理解策略模式的调度关系
- ✅ 新增文件类型只需要加一个 Strategy 类,再在工厂 Map 注册一行,主流程完全不改
- ✅ 每个策略独立可测、可复用、可组合
- ✅ 编译期就能拿到所有策略的类型信息,IDE 跳转、重构更好用
判断什么时候值得:如果分支数量 > 3 且未来还会继续增长,或者每个分支的实现细节较重(不只是 3 行),用策略模式是划算的。只有 2-3 个分支且逻辑简单,老老实实写 if-else 更可读。
总结
处理复杂 if-else 的三个层次:
- 能提前 return 就 return —— 用卫语句把边缘 case 前置,拉平主逻辑
- 能用查表就用查表 —— 简单的类型→值映射,直接用 Map / dict / switch,不写 if-else 链
- 多分支且分支重的场景用策略模式 —— 把”选择哪个分支”和”分支里做什么”分离
代码质量的一个朴素判断:一段代码从上往下读,能否像读散文一样顺畅。三层以上的嵌套 if-else 就打断了这种顺畅感,这时任何一种拆分都值得。
