策略模式(Strategy Pattern):灵活切换算法的艺术
✨ 模式简介
策略模式是一种行为型设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以互相替换。策略模式让算法的变化独立于使用它的客户端。
就像游戏中的角色可以选择不同的武器(策略),而攻击逻辑(使用策略)保持不变。
📦 应用场景
-
支付方式选择(支付宝/微信/银行卡)
-
排序算法切换(快速排序/归并排序)
-
折扣计算(满减/折扣/无优惠)
-
导航策略(步行/驾车/公共交通)
-
Spring的
Resource
资源加载策略
🧠 核心实现思路
-
策略接口:定义算法族的共同接口
-
具体策略:实现不同的算法变体
-
上下文类:持有一个策略引用,负责调用策略
🧱 策略模式的多种实现方式
1. 经典实现
// 策略接口
interface PaymentStrategy {
void pay(int amount);
}
// 具体策略
class AlipayStrategy implements PaymentStrategy {
@Override
public void pay(int amount) {
System.out.println("支付宝支付:" + amount + "元");
}
}
// 上下文
class PaymentContext {
private PaymentStrategy strategy;
public PaymentContext(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void executePayment(int amount) {
strategy.pay(amount);
}
}
// 使用
PaymentContext ctx = new PaymentContext(new AlipayStrategy());
ctx.executePayment(100);
2. 函数式编程实现(Java8+)
// 使用函数接口代替策略接口
class PaymentContext {
private Consumer<Integer> paymentStrategy;
public PaymentContext(Consumer<Integer> paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void executePayment(int amount) {
paymentStrategy.accept(amount);
}
}
// 使用Lambda表达式
PaymentContext ctx = new PaymentContext(amount ->
System.out.println("微信支付:" + amount + "元"));
ctx.executePayment(200);
3. Spring注入策略
// 策略接口
@Component
public interface DiscountStrategy {
double applyDiscount(double amount);
}
// 具体策略(带Spring注解)
@Component("vipDiscount")
public class VipDiscount implements DiscountStrategy {
@Override
public double applyDiscount(double amount) {
return amount * 0.8; // VIP打8折
}
}
// 上下文类
@Service
public class BillingService {
@Autowired
private Map<String, DiscountStrategy> strategies; // Spring自动注入所有实现
public double calculate(String strategyName, double amount) {
return strategies.get(strategyName).applyDiscount(amount);
}
}
💎 最佳实践推荐
策略+工厂模式结合
public class StrategyFactory {
private static final Map<String, PaymentStrategy> STRATEGIES = Map.of(
"alipay", new AlipayStrategy(),
"wechat", new WechatPayStrategy()
);
public static PaymentStrategy getStrategy(String type) {
return Optional.ofNullable(STRATEGIES.get(type))
.orElseThrow(() -> new IllegalArgumentException("未知支付类型"));
}
}
枚举策略(线程安全)
public enum ShippingStrategy {
EXPRESS {
public double calculate(double weight) {
return weight * 5.0;
}
},
STANDARD {
public double calculate(double weight) {
return weight * 2.5;
}
};
public abstract double calculate(double weight);
}
💣 常见问题与解决方案
问题1:如何避免if-else判断策略类型?
✅ 解决方案:
-
使用Map存储策略(如Spring自动注入)
-
结合工厂模式选择策略
问题2:策略需要共享状态怎么办?
✅ 解决方案:
-
将共享状态放入上下文类
-
使用ThreadLocal保存线程相关状态
问题3:如何动态添加新策略?
✅ 解决方案:
-
使用
ServiceLoader
机制 -
Spring中动态注册Bean
📊 模式对比
📊 策略模式实现方式对比
实现方式 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
🏛️ 经典接口实现 | ✅ 结构清晰 | ❌ 类数量多 | 传统JavaEE项目 |
🚀 函数式编程 | ✅ Lambda简洁 | ❌ 复杂逻辑难维护 | 现代Java轻量级逻辑 |
🌱 Spring注入 | ✅ 自动装配扩展方便 | ❌ 强依赖Spring容器 | Spring Boot应用 |
注:根据项目技术栈和复杂度选择合适的实现方式
📚 实际应用案例
- Java集合排序
List<Integer> nums = Arrays.asList(3,1,4);
nums.sort(Comparator.naturalOrder()); // 策略模式
- Spring资源加载
Resource resource = new ClassPathResource("app.xml"); // 策略可替换为FileSystemResource
- 电商促销活动
DiscountStrategy strategy = FestivalDiscountFactory.getStrategy("双11");
double finalPrice = strategy.applyDiscount(originalPrice);
🎯 总结建议
-
优先选择:函数式实现(Java8+)或Spring注入(企业应用)
-
性能优化:无状态策略可复用实例
-
扩展性:结合SPI机制实现动态加载
-
避免过度:简单场景可直接用条件语句
-
设计原则:符合开闭原则,新增策略无需修改上下文