策略模式如何替代if-else:从“面条代码”到Java面向对象的优雅转身
写在前面
写业务代码时,最常见的“坏味道”就是满屏的if-else。判断用户类型、计算折扣、选择支付方式……每加一种新情况,就往if-else里塞一个分支。三个月后,这个函数动辄几百行,改一处怕崩十处。更可怕的是,不同分支里还夹杂着相似的逻辑,复制粘贴成了常态。这就是典型的面向过程思维写Java。今天我们要聊的策略模式,就是专门干掉if-else的利器。再配合工厂模式,连switch都不用手写。读完这篇,你将理解什么叫“对扩展开放,对修改关闭”,以及为什么说这才是真正的Java面向对象编程。

一、什么是策略模式?
策略模式(Strategy Pattern)定义了一系列算法(或业务规则),将每个算法封装起来,并使它们可以相互替换。策略模式让算法的变化独立于使用它的客户端。

核心角色:
-
策略接口(Strategy):定义所有策略的公共方法。
-
具体策略(ConcreteStrategy):实现策略接口,封装具体算法或规则。
-
上下文(Context):持有策略对象的引用,负责调用策略。
二、为什么需要策略模式?——一个if-else的反面案例
假设我们有一个计算订单折扣的功能:
public double calculateDiscount(String userLevel, double amount) {
if ("VIP".equals(userLevel)) {
return amount * 0.8; // VIP 8折
} else if ("GOLD".equals(userLevel)) {
return amount * 0.9; // 黄金 9折
} else if ("SILVER".equals(userLevel)) {
return amount * 0.95; // 白银 95折
} else {
return amount; // 普通无折扣
}
}
痛点:
-
每增加一种用户等级,就要修改这个函数,违反开闭原则。
-
折扣算法可能在其他地方复用,只能复制粘贴。
-
单元测试需要覆盖所有分支,复杂且易遗漏。
-
多个
if-else嵌套时,代码可读性极差。
策略模式的解决方案:将每种折扣算法封装成独立的策略类,客户端根据需要选择策略。


三、策略模式的代码实现(Java)
3.1 定义策略接口
java
public interface DiscountStrategy {
double calculate(double amount);
}
3.2 实现具体策略
public class VipDiscountStrategy implements DiscountStrategy {
@Override
public double calculate(double amount) {
return amount * 0.8;
}
}
public class GoldDiscountStrategy implements DiscountStrategy {
@Override
public double calculate(double amount) {
return amount * 0.9;
}
}
public class SilverDiscountStrategy implements DiscountStrategy {
@Override
public double calculate(double amount) {
return amount * 0.95;
}
}
public class RegularDiscountStrategy implements DiscountStrategy {
@Override
public double calculate(double amount) {
return amount;
}
}
3.3 上下文类
public class OrderContext {
private DiscountStrategy strategy;
public void setStrategy(DiscountStrategy strategy) {
this.strategy = strategy;
}
public double calculateDiscount(double amount) {
return strategy.calculate(amount);
}
}
3.4 客户端使用
public class Client {
public static void main(String[] args) {
OrderContext order = new OrderContext();
// VIP用户
order.setStrategy(new VipDiscountStrategy());
System.out.println(order.calculateDiscount(100)); // 80.0
// 黄金用户
order.setStrategy(new GoldDiscountStrategy());
System.out.println(order.calculateDiscount(100)); // 90.0
}
}
问题:客户端仍然需要知道具体策略类并手动创建。这没有完全消除if-else——客户端还得判断等级然后new对应的策略。如何解决?引入工厂模式。
四、为什么要引入工厂模式?
工厂模式负责根据条件创建对应的策略对象,将“选择哪个策略”的逻辑集中到工厂中,客户端只需传入标识(如字符串、枚举),工厂返回策略实例。
4.1 简单工厂 + 策略模式
public class DiscountStrategyFactory {
public static DiscountStrategy getStrategy(String userLevel) {
switch (userLevel) {
case "VIP":
return new VipDiscountStrategy();
case "GOLD":
return new GoldDiscountStrategy();
case "SILVER":
return new SilverDiscountStrategy();
default:
return new RegularDiscountStrategy();
}
}
}
客户端变为:
String level = "VIP";
DiscountStrategy strategy = DiscountStrategyFactory.getStrategy(level);
order.setStrategy(strategy);
依然有switch,但至少集中在一处。进一步优化:使用注册表 + 反射消除switch。
4.2 使用Map注册策略(推荐)
public class DiscountStrategyFactory {
private static final Map<String, DiscountStrategy> strategies = new HashMap<>();
static {
strategies.put("VIP", new VipDiscountStrategy());
strategies.put("GOLD", new GoldDiscountStrategy());
strategies.put("SILVER", new SilverDiscountStrategy());
strategies.put("REGULAR", new RegularDiscountStrategy());
}
public static DiscountStrategy getStrategy(String userLevel) {
return strategies.getOrDefault(userLevel, strategies.get("REGULAR"));
}
}
这样,新增策略只需在Map中添加一行,无需修改工厂逻辑。完美符合开闭原则。
五、策略模式+工厂模式 = Java面向对象的极致体现
组合之后,架构清晰:

为什么说这是面向对象的体现?
-
封装:每个策略算法独立封装,互不影响。
-
继承/多态:策略接口统一,具体策略通过多态实现。
-
开闭原则:新增策略无需修改原有代码,只需添加新类+注册。
-
单一职责:每个策略类只负责一种算法;工厂只负责创建;上下文只负责委托。
六、实战:替换RAG系统中的if-else
在你的RAG项目中,可能需要对不同文档类型(PDF、Word、Markdown)采用不同的切分策略。用if-else:
if ("pdf".equals(type)) {
return parsePdf(file);
} else if ("docx".equals(type)) {
return parseDocx(file);
} else if ("md".equals(type)) {
return parseMd(file);
}
改用策略+工厂:
// 策略接口
public interface ParseStrategy {
List<String> parse(File file);
}
// 具体策略
public class PdfParseStrategy implements ParseStrategy { ... }
public class DocxParseStrategy implements ParseStrategy { ... }
// 工厂
public class ParseStrategyFactory {
private static final Map<String, ParseStrategy> map = new HashMap<>();
static {
map.put("pdf", new PdfParseStrategy());
map.put("docx", new DocxParseStrategy());
map.put("md", new MdParseStrategy());
}
public static ParseStrategy getStrategy(String type) {
return map.get(type);
}
}
// 使用
ParseStrategy strategy = ParseStrategyFactory.getStrategy(fileType);
List<String> chunks = strategy.parse(file);
从此,新增一种文档格式只需写新的策略类并在工厂注册一行。原有代码纹丝不动。
七、总结
-
策略模式:将算法封装成独立类,消除条件分支。
-
工厂模式:负责创建策略对象,解耦客户端与具体策略。
-
组合使用:既消灭了
if-else,又实现了开闭原则,是Java面向对象编程的经典实践。
下次当你看到超过3个if-else分支时,就该考虑重构为策略模式了。写出的代码将更易读、易测、易扩展。
你的项目中还有哪些地方被if-else或switch支配着?试着用策略模式重构一下,看看代码减少了多少行?或者你遇到过策略类过多导致工厂膨胀的问题吗?欢迎分享你的重构经验。
更多推荐


所有评论(0)