策略模式 (Strategy Pattern)
定义算法族,分别封装起来,让它们可以互相替换
目录
概述
策略模式是一种行为型设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以互相替换。策略模式让算法的变化独立于使用算法的客户。
适用场景
- 多种方式完成相同任务
- 需要动态切换算法
- 避免多重条件判断
基础实现
// 策略接口
public interface PaymentStrategy {
void pay(BigDecimal amount);
String getName();
}
// 具体策略:支付宝
public class AlipayStrategy implements PaymentStrategy {
@Override
public void pay(BigDecimal amount) {
System.out.println("支付宝支付: ¥" + amount);
}
@Override
public String getName() {
return "支付宝";
}
}
// 具体策略:微信支付
public class WechatPayStrategy implements PaymentStrategy {
@Override
public void pay(BigDecimal amount) {
System.out.println("微信支付: ¥" + amount);
}
@Override
public String getName() {
return "微信支付";
}
}
// 具体策略:银行卡
public class CardPayStrategy implements PaymentStrategy {
@Override
public void pay(BigDecimal amount) {
System.out.println("银行卡支付: ¥" + amount);
}
@Override
public String getName() {
return "银行卡";
}
}
// 上下文
public class PaymentContext {
private PaymentStrategy strategy;
public void setStrategy(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void executePayment(BigDecimal amount) {
strategy.pay(amount);
}
}
// 使用
PaymentContext context = new PaymentContext();
// 选择支付宝
context.setStrategy(new AlipayStrategy());
context.executePayment(new BigDecimal("100"));
// 切换到微信支付
context.setStrategy(new WechatPayStrategy());
context.executePayment(new BigDecimal("200"));Spring 集成
// 策略接口
public interface DiscountStrategy {
BigDecimal calculateDiscount(BigDecimal originalPrice);
String getType();
}
// 具体策略
@Component
public class NormalDiscountStrategy implements DiscountStrategy {
@Override
public BigDecimal calculateDiscount(BigDecimal price) {
return price; // 无折扣
}
@Override
public String getType() {
return "NORMAL";
}
}
@Component
public class VipDiscountStrategy implements DiscountStrategy {
@Override
public BigDecimal calculateDiscount(BigDecimal price) {
return price.multiply(new BigDecimal("0.8")); // VIP 8折
}
@Override
public String getType() {
return "VIP";
}
}
@Component
public class SuperVipDiscountStrategy implements DiscountStrategy {
@Override
public BigDecimal calculateDiscount(BigDecimal price) {
return price.multiply(new BigDecimal("0.5")); // 超级VIP 5折
}
@Override
public String getType() {
return "SUPER_VIP";
}
}
// 策略工厂
@Component
public class DiscountStrategyFactory {
private final Map<String, DiscountStrategy> strategies = new HashMap<>();
public DiscountStrategyFactory(List<DiscountStrategy> strategyList) {
for (DiscountStrategy strategy : strategyList) {
strategies.put(strategy.getType(), strategy);
}
}
public DiscountStrategy getStrategy(String type) {
DiscountStrategy strategy = strategies.get(type);
if (strategy == null) {
throw new IllegalArgumentException("未知的折扣类型: " + type);
}
return strategy;
}
}
// 使用
@Service
public class OrderService {
@Autowired
private DiscountStrategyFactory strategyFactory;
public BigDecimal calculatePrice(String userType, BigDecimal originalPrice) {
DiscountStrategy strategy = strategyFactory.getStrategy(userType);
return strategy.calculateDiscount(originalPrice);
}
}框架中的应用
Java Comparator
// Comparator 是策略接口
List<String> names = Arrays.asList("Tom", "JERRY", "alice");
// 策略1:自然排序
names.sort(Comparator.naturalOrder());
// 策略2:忽略大小写
names.sort(String.CASE_INSENSITIVE_ORDER);
// 策略3:按长度排序
names.sort(Comparator.comparingInt(String::length));
// 策略4:自定义排序
names.sort((a, b) -> a.length() - b.length());Spring Validation
// Spring 的 Validator 是策略模式
public interface Validator {
boolean supports(Class<?> clazz);
void validate(Object target, Errors errors);
}
// 不同的验证器实现不同的验证策略
@Component
public class UserValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return User.class.equals(clazz);
}
@Override
public void validate(Object target, Errors errors) {
// 验证逻辑
}
}ThreadPoolExecutor 拒绝策略
// 拒绝策略枚举
new ThreadPoolExecutor(
5, 10, 60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100),
// 选择拒绝策略
new ThreadPoolExecutor.CallerRunsPolicy() // 调用者执行
// new ThreadPoolExecutor.AbortPolicy() // 抛出异常
// new ThreadPoolExecutor.DiscardPolicy() // 静默丢弃
// new ThreadPoolExecutor.DiscardOldestPolicy() // 丢弃最老任务
);实际应用:排序策略
// 排序策略接口
public interface SortStrategy {
<T extends Comparable<T>> void sort(List<T> list);
String getName();
}
// 快速排序
@Component
public class QuickSortStrategy implements SortStrategy {
@Override
public <T extends Comparable<T>> void sort(List<T> list) {
quickSort(list, 0, list.size() - 1);
}
private <T extends Comparable<T>> void quickSort(List<T> list, int low, int high) {
if (low < high) {
int pi = partition(list, low, high);
quickSort(list, low, pi - 1);
quickSort(list, pi + 1, high);
}
}
private <T extends Comparable<T>> int partition(List<T> list, int low, int high) {
T pivot = list.get(high);
int i = low - 1;
for (int j = low; j < high; j++) {
if (list.get(j).compareTo(pivot) <= 0) {
i++;
Collections.swap(list, i, j);
}
}
Collections.swap(list, i + 1, high);
return i + 1;
}
@Override
public String getName() {
return "QUICK_SORT";
}
}
// 归并排序
@Component
public class MergeSortStrategy implements SortStrategy {
@Override
public <T extends Comparable<T>> void sort(List<T> list) {
if (list.size() > 1) {
mergeSort(list, 0, list.size() - 1);
}
}
// 实现归并排序...
@Override
public String getName() {
return "MERGE_SORT";
}
}
// 排序服务
@Service
public class SortService {
@Autowired
private Map<String, SortStrategy> strategies;
public <T extends Comparable<T>> List<T> sort(List<T> list, String algorithm) {
SortStrategy strategy = strategies.get(algorithm);
if (strategy == null) {
throw new IllegalArgumentException("未知的排序算法");
}
List<T> copy = new ArrayList<>(list);
strategy.sort(copy);
return copy;
}
}与状态模式对比
| 策略模式 | 状态模式 |
|---|---|
| 客户端选择算法 | 状态自动转换 |
| 算法平等独立 | 状态有先后顺序 |
| 替换整个算法 | 根据条件改变行为 |
优缺点
| 优点 | 缺点 |
|---|---|
| 消除条件判断 | 类数量增加 |
| 易于扩展 | 客户端需了解策略 |
| 复用性好 |
总结
策略模式是消除 if-else/switch 的有效手段。在 Spring 中结合依赖注入可以实现优雅的策略管理。注意策略数量过多时考虑使用工厂模式管理。