策略模式
策略模式用于定义一组可互换的算法或规则,并在运行时选择其中一种执行。
一句话理解:把一堆 if-else 里的算法拆成独立策略。
解决什么问题
支付、折扣、路由、导出、计算规则等业务经常会出现这样的代码:
java
if ("vip".equals(type)) {
// vip discount
} else if ("new_user".equals(type)) {
// new user discount
} else if ("festival".equals(type)) {
// festival discount
}当规则越来越多时,主流程会变得很难维护。策略模式把每种算法封装成一个类,让主流程只负责选择和调用。
基本结构
text
Context -> Strategy
^
|
ConcreteStrategy角色:
Strategy:策略接口。ConcreteStrategy:具体策略。Context:上下文,选择并执行策略。
Java 示例
策略接口:
java
interface DiscountStrategy {
String type();
int discount(int originAmount);
}具体策略:
java
class VipDiscountStrategy implements DiscountStrategy {
public String type() {
return "vip";
}
public int discount(int originAmount) {
return (int) (originAmount * 0.8);
}
}
class NewUserDiscountStrategy implements DiscountStrategy {
public String type() {
return "new_user";
}
public int discount(int originAmount) {
return originAmount - 1000;
}
}策略上下文:
java
import java.util.HashMap;
import java.util.List;
import java.util.Map;
class DiscountService {
private final Map<String, DiscountStrategy> strategyMap = new HashMap<>();
DiscountService(List<DiscountStrategy> strategies) {
for (DiscountStrategy strategy : strategies) {
strategyMap.put(strategy.type(), strategy);
}
}
public int calculate(String type, int originAmount) {
DiscountStrategy strategy = strategyMap.get(type);
if (strategy == null) {
throw new IllegalArgumentException("unsupported discount type: " + type);
}
return strategy.discount(originAmount);
}
}使用:
java
import java.util.Arrays;
DiscountService service = new DiscountService(Arrays.asList(
new VipDiscountStrategy(),
new NewUserDiscountStrategy()
));
int amount = service.calculate("vip", 10000);Spring 中的常见写法
在 Spring 中,可以把所有策略注入进来:
java
@Service
public class DiscountService {
private final Map<String, DiscountStrategy> strategyMap;
public DiscountService(List<DiscountStrategy> strategies) {
this.strategyMap = strategies.stream()
.collect(Collectors.toMap(DiscountStrategy::type, Function.identity()));
}
}新增策略时,只要新增一个实现类并交给 Spring 管理。
使用场景
- 优惠计算。
- 支付渠道。
- 文件导出。
- 消息发送渠道。
- 排序算法。
- 规则路由。
- 根据类型选择不同处理逻辑。
优点
- 消除复杂
if-else。 - 每个策略独立维护。
- 新增策略不影响主流程。
- 方便单独测试每个策略。
缺点
- 策略类数量会增加。
- 调用方或上下文需要知道选择哪种策略。
- 策略之间如果有大量重复代码,需要再抽公共逻辑。
和工厂模式的关系
策略模式负责“怎么做”,工厂模式负责“创建谁”。
实际项目中经常组合使用:
text
工厂/Map 找到策略
策略执行具体算法实战注意
策略模式最适合替换同一业务点上的多种算法。如果这些分支逻辑并不属于同一抽象,强行抽成策略会让代码更绕。