策略模式
问题
什么是策略模式?Java / Spring 项目中如何使用策略模式消除 if-else?
答案
核心思想
将一组算法封装成独立的策略类,使它们可以互相替换。客户端不关心具体使用哪个算法,运行时动态选择。
基础实现
策略模式消除 if-else
// 策略接口
public interface PricingStrategy {
BigDecimal calculate(BigDecimal price);
}
// 普通会员:不打折
public class NormalPricing implements PricingStrategy {
@Override
public BigDecimal calculate(BigDecimal price) {
return price;
}
}
// VIP 会员:打 8 折
public class VipPricing implements PricingStrategy {
@Override
public BigDecimal calculate(BigDecimal price) {
return price.multiply(new BigDecimal("0.8"));
}
}
// SVIP:打 6 折
public class SvipPricing implements PricingStrategy {
@Override
public BigDecimal calculate(BigDecimal price) {
return price.multiply(new BigDecimal("0.6"));
}
}
Spring 中自动收集策略
利用 Spring IoC 自动注入所有策略实现,避免手动维护 Map。
Spring 自动收集 + 策略工厂
// 在每个策略上标注类型
public interface PricingStrategy {
String getType(); // 返回策略标识
BigDecimal calculate(BigDecimal price);
}
@Component
public class NormalPricing implements PricingStrategy {
@Override
public String getType() { return "NORMAL"; }
@Override
public BigDecimal calculate(BigDecimal price) { return price; }
}
// 策略工厂:Spring 自动注入所有实现
@Component
public class PricingStrategyFactory {
private final Map<String, PricingStrategy> strategyMap;
// Spring 会自动注入所有 PricingStrategy 实现
public PricingStrategyFactory(List<PricingStrategy> strategies) {
this.strategyMap = strategies.stream()
.collect(Collectors.toMap(PricingStrategy::getType, Function.identity()));
}
public PricingStrategy get(String type) {
PricingStrategy strategy = strategyMap.get(type);
if (strategy == null) {
throw new IllegalArgumentException("不支持的策略类型: " + type);
}
return strategy;
}
}
// 使用:新增策略只需加一个类,无需修改任何已有代码
@Service
public class OrderService {
@Autowired
private PricingStrategyFactory factory;
public BigDecimal calculatePrice(String memberType, BigDecimal price) {
return factory.get(memberType).calculate(price);
}
}
为什么比 if-else 好?
- 开闭原则:新增策略只加一个类,不改已有代码
- 单一职责:每个策略类只管一件事
- 易于测试:每个策略可以独立单测
常见面试问题
Q1: 策略模式和工厂模式的区别?
答案:
| 维度 | 工厂模式 | 策略模式 |
|---|---|---|
| 关注点 | 创建对象 | 选择算法 |
| 结果 | 返回不同类型的产品 | 执行不同的行为 |
| 典型场景 | 根据类型创建对象 | 根据条件执行不同算法 |
实际项目中经常组合使用:工厂负责创建策略对象,策略负责执行具体逻辑。
Q2: 策略模式在 Java 中有哪些典型应用?
答案:
Comparator:不同排序策略(Collections.sort(list, comparator))ThreadPoolExecutor拒绝策略:4 种RejectedExecutionHandler- Spring
Resource:ClassPathResource、FileSystemResource、UrlResource - 支付、物流、定价等业务场景
Q3: 如何用枚举实现简单的策略模式?
答案:
public enum DiscountStrategy {
NORMAL {
@Override
public BigDecimal apply(BigDecimal price) { return price; }
},
VIP {
@Override
public BigDecimal apply(BigDecimal price) {
return price.multiply(new BigDecimal("0.8"));
}
};
public abstract BigDecimal apply(BigDecimal price);
}
// 使用
BigDecimal finalPrice = DiscountStrategy.valueOf("VIP").apply(price);
适合策略数量固定且逻辑简单的场景。