1. 策略模式概述
策略模式(Strategy Pattern)是行为型设计模式中最常用的模式之一,它定义了算法家族,分别封装起来,让它们之间可以互相替换。这种模式的核心在于将算法的使用与实现分离,使得算法可以独立于使用它的客户端变化。
在实际开发中,我们经常会遇到需要根据不同条件执行不同算法的情况。比如电商平台的促销策略(满减、折扣、赠品)、支付方式选择(支付宝、微信、银联)、文件压缩算法(ZIP、RAR、7z)等场景。如果直接在业务代码中使用if-else或switch-case来处理这些分支,会导致代码臃肿且难以维护。策略模式正是为了解决这类问题而生的。
提示:策略模式与简单工厂模式经常被混淆,但二者有本质区别。工厂模式关注对象的创建,而策略模式关注行为的封装和替换。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 策略模式的核心结构
2.1 UML类图解析
策略模式的经典UML类图包含三个核心角色:
-
Context(环境类):持有一个Strategy的引用,负责与具体策略类交互。通常Context会提供一个接口让Strategy访问它的数据。
-
Strategy(抽象策略类):定义所有支持的算法的公共接口,Context使用这个接口调用具体策略类定义的算法。
-
ConcreteStrategy(具体策略类):实现Strategy接口的具体算法。
mermaid复制classDiagram
class Context {
-strategy: Strategy
+setStrategy(Strategy)
+executeStrategy()
}
class Strategy {
<<interface>>
+execute()
}
class ConcreteStrategyA {
+execute()
}
class ConcreteStrategyB {
+execute()
}
Context --> Strategy
Strategy <|-- ConcreteStrategyA
Strategy <|-- ConcreteStrategyB
2.2 代码实现示例
以下是一个完整的Java实现示例,模拟电商促销场景:
java复制// 抽象策略接口
public interface PromotionStrategy {
BigDecimal applyPromotion(BigDecimal price);
}
// 具体策略类:无促销
public class NoPromotion implements PromotionStrategy {
@Override
public BigDecimal applyPromotion(BigDecimal price) {
return price;
}
}
// 具体策略类:满减
public class FullReductionPromotion implements PromotionStrategy {
private final BigDecimal condition;
private final BigDecimal reduction;
public FullReductionPromotion(BigDecimal condition, BigDecimal reduction) {
this.condition = condition;
this.reduction = reduction;
}
@Override
public BigDecimal applyPromotion(BigDecimal price) {
return price.compareTo(condition) >= 0 ? price.subtract(reduction) : price;
}
}
// 具体策略类:折扣
public class DiscountPromotion implements PromotionStrategy {
private final BigDecimal discount;
public DiscountPromotion(BigDecimal discount) {
this.discount = discount;
}
@Override
public BigDecimal applyPromotion(BigDecimal price) {
return price.multiply(discount);
}
}
// 环境类
public class PromotionContext {
private PromotionStrategy strategy;
public PromotionContext(PromotionStrategy strategy) {
this.strategy = strategy;
}
public void setStrategy(PromotionStrategy strategy) {
this.strategy = strategy;
}
public BigDecimal executeStrategy(BigDecimal price) {
return strategy.applyPromotion(price);
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
PromotionContext context = new PromotionContext(new NoPromotion());
System.out.println("原价100,无促销: " + context.executeStrategy(new BigDecimal("100")));
context.setStrategy(new FullReductionPromotion(new BigDecimal("100"), new BigDecimal("20")));
System.out.println("满100减20: " + context.executeStrategy(new BigDecimal("120")));
context.setStrategy(new DiscountPromotion(new BigDecimal("0.8")));
System.out.println("8折优惠: " + context.executeStrategy(new BigDecimal("100")));
}
}
3. 策略模式的进阶应用
3.1 策略枚举实现
对于策略相对固定且简单的场景,可以使用枚举来实现策略模式,既简洁又避免了类的膨胀:
java复制public enum Calculator {
ADD {
@Override
public int exec(int a, int b) {
return a + b;
}
},
SUB {
@Override
public int exec(int a, int b) {
return a - b;
}
};
public abstract int exec(int a, int b);
}
// 使用示例
int result = Calculator.ADD.exec(1, 2);
3.2 Spring中的策略模式
在Spring框架中,策略模式被广泛应用。一个典型例子是ResourceLoader接口和它的不同实现:
java复制// Spring资源加载策略
Resource resource = new ClassPathResource("applicationContext.xml");
Resource resource2 = new FileSystemResource("/conf/applicationContext.xml");
Resource resource3 = new UrlResource("http://www.example.com/resource.xml");
Spring还提供了Strategy接口的自动注入能力,可以非常方便地实现策略模式的扩展:
java复制@Service
public class PaymentService {
private Map<String, PaymentStrategy> strategies;
@Autowired
public PaymentService(List<PaymentStrategy> strategyList) {
strategies = strategyList.stream()
.collect(Collectors.toMap(
s -> s.getClass().getAnnotation(PaymentType.class).value(),
Function.identity()
));
}
public void pay(String type, BigDecimal amount) {
PaymentStrategy strategy = strategies.get(type);
if (strategy == null) {
throw new IllegalArgumentException("Unsupported payment type");
}
strategy.pay(amount);
}
}
public interface PaymentStrategy {
void pay(BigDecimal amount);
}
@PaymentType("alipay")
@Service
public class AlipayStrategy implements PaymentStrategy {
@Override
public void pay(BigDecimal amount) {
// 支付宝支付逻辑
}
}
@PaymentType("wechat")
@Service
public class WechatPayStrategy implements PaymentStrategy {
@Override
public void pay(BigDecimal amount) {
// 微信支付逻辑
}
}
3.3 策略模式与Lambda表达式
Java 8引入的Lambda表达式让策略模式的实现更加简洁:
java复制public class StrategyWithLambda {
private final Map<String, Function<BigDecimal, BigDecimal>> strategies = new HashMap<>();
public StrategyWithLambda() {
strategies.put("noPromotion", price -> price);
strategies.put("fullReduction", price ->
price.compareTo(new BigDecimal("100")) >= 0 ?
price.subtract(new BigDecimal("20")) : price);
strategies.put("discount", price -> price.multiply(new BigDecimal("0.8")));
}
public BigDecimal applyPromotion(String strategyName, BigDecimal price) {
return strategies.getOrDefault(strategyName, p -> p).apply(price);
}
}
4. 策略模式的优缺点与适用场景
4.1 优势分析
- 开闭原则:可以在不修改原有代码的情况下灵活增加新策略
- 消除条件语句:避免了大量的if-else或switch-case语句
- 算法复用:相同策略可以被不同环境类使用
- 单元测试友好:每个策略可以独立测试
- 运行时切换:可以在运行时
