1. 为什么策略模式是Java开发者的必备技能
第一次接触策略模式是在我刚工作那年接手的一个电商促销系统。当时系统里有几十个if-else判断不同用户类型的折扣计算逻辑,每次新增活动类型都要在原有代码上打补丁。直到我的导师指着那段300行的代码说:"这里该用策略模式了",我才意识到设计模式不是教科书里的理论,而是解决实际痛点的利器。
策略模式(Strategy Pattern)属于行为型设计模式,它定义了算法家族并分别封装起来,让它们可以互相替换。这种模式让算法的变化独立于使用算法的客户端——就像给手机换APP不需要换手机本身。在Java开发中,策略模式特别适合处理:
- 同一问题存在多种解决方案的场景(如支付方式、排序算法)
- 需要动态切换算法行为的场景(如游戏难度调整)
- 存在大量条件判断语句的场景(如我遇到的那个促销系统)
提示:当你发现自己在不断修改同一段代码来添加新行为时,就是考虑策略模式的信号
2. 策略模式的三大核心组件
2.1 策略接口:定义作战计划
策略接口是模式中的"宪法",它用抽象方法规定了所有具体策略必须实现的操作。在Java中我们通常用接口定义:
public interface DiscountStrategy { double applyDiscount(double originalPrice); }这个简单的接口却蕴含了重要设计思想:
- 方法命名要体现业务语义(applyDiscount比calculate更直观)
- 参数设计要足够通用(原始价格而非订单对象,降低耦合)
- 返回类型要明确(避免用Object这类模糊类型)
2.2 具体策略类:特种部队实现
每个具体策略都是接口的一个实现,像不同的特种部队:
// 普通会员策略 public class RegularMemberDiscount implements DiscountStrategy { @Override public double applyDiscount(double originalPrice) { return originalPrice * 0.9; // 打9折 } } // VIP会员策略 public class VipMemberDiscount implements DiscountStrategy { @Override public double applyDiscount(double originalPrice) { return originalPrice * 0.7; // 打7折 } }实际开发中容易踩的坑:
- 避免策略类持有状态(应设计为无状态类)
- 策略逻辑应该纯粹(不要混入业务校验等无关逻辑)
- 考虑线程安全性(特别是使用了共享数据时)
2.3 上下文类:战地指挥官
Context类是使用策略的入口,它有两个关键职责:
public class DiscountContext { private DiscountStrategy strategy; // 设置策略(注入点) public void setStrategy(DiscountStrategy strategy) { this.strategy = strategy; } // 执行策略 public double executeStrategy(double price) { if(strategy == null) { throw new IllegalStateException("未设置折扣策略"); } return strategy.applyDiscount(price); } }我在实际项目中总结的最佳实践:
- 上下文应该对客户端隐藏策略的创建细节
- 可以结合工厂模式来管理策略实例
- 添加合理的空策略检查(如上面的异常抛出)
3. 从零实现策略模式的完整流程
3.1 环境准备与基础搭建
首先确保你的Java开发环境就绪:
- JDK 8+(推荐JDK 11 LTS版本)
- IDE(IntelliJ IDEA或Eclipse)
- Maven/Gradle构建工具
创建Maven项目的基本结构:
strategy-demo ├── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ └── example │ │ │ ├── strategy │ │ │ └── Main.java │ │ └── resources │ └── test │ └── java3.2 完整代码实现示例
我们用一个电商折扣系统来演示完整实现:
// 策略接口 public interface DiscountStrategy { String getType(); double applyDiscount(double originalPrice); } // 具体策略实现 public class NewUserDiscount implements DiscountStrategy { @Override public String getType() { return "NEW_USER"; } @Override public double applyDiscount(double price) { return price * 0.8; // 新用户8折 } } public class FestivalDiscount implements DiscountStrategy { @Override public String getType() { return "FESTIVAL"; } @Override public double applyDiscount(double price) { return price > 100 ? price - 20 : price; // 满100减20 } } // 上下文类增强版 public class DiscountContext { private final Map<String, DiscountStrategy> strategies = new HashMap<>(); public void addStrategy(DiscountStrategy strategy) { strategies.put(strategy.getType(), strategy); } public double applyDiscount(String type, double price) { DiscountStrategy strategy = strategies.get(type); if(strategy == null) { throw new IllegalArgumentException("无效的折扣类型: " + type); } return strategy.applyDiscount(price); } } // 客户端使用 public class Client { public static void main(String[] args) { DiscountContext context = new DiscountContext(); context.addStrategy(new NewUserDiscount()); context.addStrategy(new FestivalDiscount()); double newUserPrice = context.applyDiscount("NEW_USER", 200); System.out.println("新用户价格: " + newUserPrice); } }3.3 运行与测试
在IDE中直接运行Client类,你应该能看到输出:
新用户价格: 160.0进阶验证建议:
- 添加JUnit测试验证各种边界条件
- 尝试添加新的折扣策略(如季节性折扣)
- 测试传入无效策略类型时的处理
4. 策略模式在Spring中的实战应用
4.1 结合Spring的依赖注入
在现代Java开发中,我们通常会用Spring框架来管理策略:
@Service public class DiscountService { private final Map<String, DiscountStrategy> strategies; @Autowired public DiscountService(List<DiscountStrategy> strategyList) { this.strategies = strategyList.stream() .collect(Collectors.toMap( DiscountStrategy::getType, Function.identity() )); } public double applyDiscount(String type, double price) { DiscountStrategy strategy = strategies.get(type); if(strategy == null) { throw new IllegalArgumentException("不支持的折扣类型"); } return strategy.applyDiscount(price); } }Spring会自动将所有实现DiscountStrategy的Bean注入到List中,我们将其转换为Map方便查找。这种方式的好处是:
- 新增策略只需添加新的实现类
- 不需要修改现有代码
- 策略的创建由Spring容器管理
4.2 策略模式与Spring Boot的完美结合
在Spring Boot项目中,我们可以做得更优雅:
- 定义策略接口:
public interface PaymentStrategy { String getType(); PaymentResult process(PaymentRequest request); }- 实现具体策略(以支付宝支付为例):
@Service public class AlipayStrategy implements PaymentStrategy { @Override public String getType() { return "ALIPAY"; } @Override public PaymentResult process(PaymentRequest request) { // 调用支付宝SDK的具体实现 return new PaymentResult(true, "支付宝支付成功"); } }- 创建策略路由器:
@Service public class PaymentRouter { private final Map<String, PaymentStrategy> strategies; public PaymentRouter(List<PaymentStrategy> strategyList) { this.strategies = strategyList.stream() .collect(Collectors.toMap( PaymentStrategy::getType, Function.identity() )); } public PaymentResult executePayment(String type, PaymentRequest request) { PaymentStrategy strategy = strategies.get(type); if(strategy == null) { throw new PaymentException("不支持的支付方式"); } return strategy.process(request); } }- 在Controller中使用:
@RestController @RequestMapping("/payments") public class PaymentController { @Autowired private PaymentRouter paymentRouter; @PostMapping public ResponseEntity<?> pay(@RequestBody PaymentRequest request) { try { PaymentResult result = paymentRouter.executePayment( request.getPaymentType(), request ); return ResponseEntity.ok(result); } catch (PaymentException e) { return ResponseEntity.badRequest().body(e.getMessage()); } } }这种实现方式的优势:
- 完全符合开闭原则(对扩展开放,对修改关闭)
- 策略之间完全解耦
- 便于单元测试
- 新增支付方式只需添加新策略实现
5. 策略模式的高级应用与性能优化
5.1 策略模式的五种高级用法
- 策略+工厂模式:集中管理策略实例的创建
public class StrategyFactory { private static final Map<String, DiscountStrategy> STRATEGIES = Map.of( "VIP", new VipDiscount(), "NEW", new NewUserDiscount() ); public static DiscountStrategy getStrategy(String type) { DiscountStrategy strategy = STRATEGIES.get(type); if(strategy == null) { throw new IllegalArgumentException("未知策略类型"); } return strategy; } }- 策略+模板方法模式:在策略中复用公共逻辑
public abstract class AbstractDiscount implements DiscountStrategy { // 公共前置处理 protected void beforeApply() { System.out.println("开始计算折扣..."); } // 公共后置处理 protected void afterApply() { System.out.println("折扣计算完成"); } @Override public final double applyDiscount(double price) { beforeApply(); double result = doApply(price); afterApply(); return result; } protected abstract double doApply(double price); }- 策略+组合模式:构建策略树处理复杂场景
public class CompositeDiscount implements DiscountStrategy { private final List<DiscountStrategy> strategies; public CompositeDiscount(List<DiscountStrategy> strategies) { this.strategies = strategies; } @Override public double applyDiscount(double price) { double result = price; for(DiscountStrategy strategy : strategies) { result = strategy.applyDiscount(result); } return result; } }- 策略+享元模式:优化大量策略实例的性能
public class StrategyFlyweight { private static final Map<String, DiscountStrategy> POOL = new HashMap<>(); public static DiscountStrategy getStrategy(String type) { return POOL.computeIfAbsent(type, key -> { switch(key) { case "VIP": return new VipDiscount(); case "NEW": return new NewUserDiscount(); default: throw new IllegalArgumentException(); } }); } }- 策略+注解驱动:更优雅的策略注册方式
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface StrategyType { String value(); } @StrategyType("VIP") public class VipDiscount implements DiscountStrategy { // 实现代码 } // 在工厂类中扫描注解 public class AnnotationStrategyFactory { public static void registerStrategies(String packageName) { Reflections reflections = new Reflections(packageName); Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(StrategyType.class); annotated.forEach(clazz -> { StrategyType annotation = clazz.getAnnotation(StrategyType.class); // 注册策略 }); } }5.2 策略模式的性能优化技巧
- 策略对象的复用:
- 无状态策略可以设计为单例
- 使用对象池管理有状态策略
- Spring中默认单例作用域足够应对大多数场景
- 策略选择的优化:
// 使用枚举代替字符串查找 public enum DiscountType { VIP(new VipDiscount()), NEW(new NewUserDiscount()); private final DiscountStrategy strategy; DiscountType(DiscountStrategy strategy) { this.strategy = strategy; } public DiscountStrategy getStrategy() { return strategy; } } // 使用方式 double discount = DiscountType.VIP.getStrategy().applyDiscount(price);- 避免的策略模式误用:
- 策略类不宜过多(超过20个考虑分类分层)
- 不要滥用策略模式处理简单条件分支
- 策略接口不应过度膨胀(遵循单一职责)
- JMH性能测试示例:
@BenchmarkMode(Mode.Throughput) @OutputTimeUnit(TimeUnit.MILLISECONDS) public class StrategyBenchmark { @State(Scope.Thread) public static class ExecutionPlan { public DiscountContext context = new DiscountContext(); public double price = 100.0; @Setup public void setup() { context.addStrategy(new VipDiscount()); context.addStrategy(new NewUserDiscount()); } } @Benchmark public double benchmarkVip(ExecutionPlan plan) { return plan.context.applyDiscount("VIP", plan.price); } }6. 策略模式在真实项目中的经典案例
6.1 电商平台中的定价策略
某大型电商平台的商品定价系统:
- 基础价格策略(成本加成)
- 促销策略(满减、折扣)
- 会员策略(等级折扣)
- 地区策略(区域定价)
- 组合策略(多种策略叠加)
public class PriceCalculator { private final List<PricingStrategy> strategies; public PriceCalculator(List<PricingStrategy> strategies) { this.strategies = strategies; } public BigDecimal calculate(Product product, User user) { BigDecimal price = product.getBasePrice(); for(PricingStrategy strategy : strategies) { price = strategy.apply(product, user, price); } return price; } }6.2 游戏开发中的AI行为策略
一款RPG游戏中NPC的AI系统:
- 攻击策略(近战、远程、魔法)
- 移动策略(追击、逃跑、巡逻)
- 对话策略(友好、敌对、中立)
public class NpcController { private CombatStrategy combatStrategy; private MovementStrategy movementStrategy; public void update(GameContext context) { movementStrategy.move(context); combatStrategy.attack(context); } // 根据游戏状态切换策略 public void adjustStrategies(GameState state) { if(state.isLowHealth()) { combatStrategy = new DefensiveCombat(); movementStrategy = new RetreatMovement(); } else { combatStrategy = new AggressiveCombat(); movementStrategy = new PatrolMovement(); } } }6.3 金融系统中的风控策略
支付风控系统的策略实现:
- 基础风控策略(金额限制、频次控制)
- 行为风控策略(异常行为检测)
- 信用风控策略(用户信用评估)
- 组合风控策略(多策略联合决策)
public class RiskControlService { private final List<RiskStrategy> strategies; public RiskResult check(PaymentRequest request) { RiskResult result = new RiskResult(); for(RiskStrategy strategy : strategies) { strategy.evaluate(request, result); if(result.isBlocked()) { break; // 任一策略拦截则终止 } } return result; } }6.4 物流系统中的运费计算
跨境电商的运费计算模块:
- 重量策略(按重量计费)
- 体积策略(按体积计费)
- 地区策略(目的地运费系数)
- 快递策略(不同快递公司报价)
- 促销策略(包邮活动)
public class ShippingFeeCalculator { public BigDecimal calculate(Order order) { ShippingStrategy strategy = determineMainStrategy(order); BigDecimal fee = strategy.calculate(order); // 应用附加策略 for(ShippingDecorator decorator : decorators) { fee = decorator.decorate(fee, order); } return fee; } private ShippingStrategy determineMainStrategy(Order order) { if(order.isOversized()) { return new VolumetricStrategy(); } return new WeightStrategy(); } }7. 策略模式常见问题与解决方案
7.1 如何管理策略的创建?
问题场景:当策略需要复杂初始化时,直接在客户端创建会导致代码耦合。
解决方案:
- 使用工厂模式封装创建逻辑
- 依赖注入(如Spring的@Bean配置)
- 原型模式(需要时克隆已有策略)
// 基于工厂的解决方案 public class StrategyFactory { private final Config config; public StrategyFactory(Config config) { this.config = config; } public DiscountStrategy create(String type) { switch(type) { case "VIP": return new VipDiscount(config.getVipDiscountRate()); case "SEASONAL": return new SeasonalDiscount(config.getSeasonalRules()); default: throw new IllegalArgumentException("未知策略类型"); } } }7.2 如何处理策略间的共享数据?
问题场景:多个策略需要访问相同数据,但又不希望策略间直接耦合。
解决方案:
- 将共享数据放入上下文对象
- 使用ThreadLocal保存线程级共享数据
- 设计无状态策略+外部数据源
public class PricingContext { private final Product product; private final User user; private final Map<String, Object> attributes = new HashMap<>(); // getters/setters } public interface PricingStrategy { BigDecimal calculate(PricingContext context); }7.3 如何实现策略的动态替换?
问题场景:需要在运行时根据条件切换策略,而不重启应用。
解决方案:
- 结合配置中心(如Nacos、Apollo)
- 使用热部署技术(如JRebel)
- 设计支持动态注册的策略管理器
public class DynamicStrategyManager { private final Map<String, DiscountStrategy> strategies = new ConcurrentHashMap<>(); public void register(String type, DiscountStrategy strategy) { strategies.put(type, strategy); } public void unregister(String type) { strategies.remove(type); } public DiscountStrategy get(String type) { return strategies.get(type); } }7.4 如何避免策略类爆炸?
问题场景:当业务复杂时,策略类数量可能急剧增长。
解决方案:
- 使用策略层次结构(继承体系)
- 组合模式构建复合策略
- 按业务域划分策略包
// 策略层次结构示例 public abstract class BaseDiscount implements DiscountStrategy { protected double baseRate; public BaseDiscount(double baseRate) { this.baseRate = baseRate; } } public class TieredDiscount extends BaseDiscount { private final Map<Double, Double> tierRates; public TieredDiscount(double baseRate, Map<Double, Double> tierRates) { super(baseRate); this.tierRates = tierRates; } @Override public double applyDiscount(double price) { // 实现分层折扣逻辑 } }8. 策略模式的最佳实践与反模式
8.1 十大最佳实践
- 接口设计原则:
- 策略接口应该小而专注(单一职责)
- 方法签名要面向业务而非实现
- 考虑添加策略标识方法(如getType())
- 上下文设计技巧:
- 提供默认策略
- 支持策略链式调用
- 添加策略执行前后的钩子方法
- 性能优化建议:
- 无状态策略使用单例
- 频繁创建的策略考虑对象池
- 策略选择使用枚举而非字符串
- 测试指导方针:
- 为每个策略编写独立测试用例
- 测试上下文类的策略切换逻辑
- 模拟策略执行失败场景
- 文档规范:
- 为每个策略添加使用场景说明
- 记录策略间的互斥关系
- 注明线程安全性要求
- 与其它模式的协作:
- 工厂模式管理策略创建
- 模板方法模式提取公共逻辑
- 装饰器模式增强策略功能
- 异常处理策略:
- 定义策略专属异常类型
- 上下文处理策略执行异常
- 添加策略降级机制
- 日志记录建议:
- 记录策略切换事件
- 跟踪策略执行耗时
- 标记策略执行失败
- 监控指标设计:
- 策略调用次数
- 策略执行耗时
- 策略失败率
- 演进路线规划:
- 预留策略版本字段
- 设计策略兼容方案
- 制定策略废弃流程
8.2 五大常见反模式
- 上帝策略:
- 症状:单个策略类实现过多不相关功能
- 解决:按单一职责原则拆分策略
- 策略贫血症:
- 症状:策略接口过于简单,导致上下文逻辑膨胀
- 解决:将相关行为移入策略接口
- 策略耦合:
- 症状:策略之间直接互相调用
- 解决:通过上下文共享数据,或使用中介者模式
- 策略泛滥:
- 症状:为每个微小变化创建新策略
- 解决:使用策略参数化或配置化
- 空策略综合症:
- 症状:大量策略类只做简单条件转发
- 解决:合并简单策略,或改用规则引擎
9. 策略模式面试深度解析
9.1 高频面试题精讲
问题1:策略模式和工厂模式有什么区别?
深度解析:
- 目的不同:
- 工厂关注对象创建
- 策略关注行为封装
- 使用时机:
- 工厂在实例化时决定
- 策略在运行时决定
- 关系:
- 常组合使用(工厂创建策略)
- 代码表现:
- 工厂方法通常返回具体对象
- 策略方法执行算法
问题2:什么情况下不应该使用策略模式?
避坑指南:
- 当只有一两种固定算法时(过度设计)
- 算法非常简单(if-else足够)
- 策略需要访问大量上下文私有状态(破坏封装)
- 性能敏感场景(虚方法调用开销)
- 算法很少变化(维护成本高于收益)
问题3:如何测试策略模式实现?
测试方案:
- 单元测试每个具体策略
- 测试上下文类的策略切换
- 模拟策略执行异常
- 性能测试策略选择机制
- 集成测试多策略组合
// 示例测试代码 @Test public void testVipStrategy() { DiscountStrategy strategy = new VipDiscount(); assertEquals(90, strategy.applyDiscount(100), 0.001); } @Test public void testContextStrategySwitch() { DiscountContext context = new DiscountContext(); context.setStrategy(new VipDiscount()); assertEquals(90, context.executeStrategy(100), 0.001); context.setStrategy(new NewUserDiscount()); assertEquals(80, context.executeStrategy(100), 0.001); }9.2 设计模式组合实战
场景:电商平台优惠系统需要支持:
- 多种优惠策略(满减、折扣、赠品)
- 策略优先级配置
- 策略冲突检测
- 策略效果分析
解决方案设计:
- 策略模式实现基础优惠策略
- 责任链模式处理策略优先级
- 组合模式支持策略包
- 观察者模式记录策略应用
// 组合模式示例 public class CompositePromotion implements PromotionStrategy { private final List<PromotionStrategy> strategies; public CompositePromotion(List<PromotionStrategy> strategies) { this.strategies = strategies; } @Override public PromotionResult apply(Order order) { PromotionResult result = new PromotionResult(); for(PromotionStrategy strategy : strategies) { result.combine(strategy.apply(order)); } return result; } } // 责任链模式示例 public abstract class PromotionHandler { private PromotionHandler next; public void setNext(PromotionHandler next) { this.next = next; } public PromotionResult handle(Order order) { PromotionResult result = applyPromotion(order); if(next != null) { result.combine(next.handle(order)); } return result; } protected abstract PromotionResult applyPromotion(Order order); }9.3 架构师级思考题
问题:如何设计支持百万级QPS的策略服务?
高性能设计方案:
- 策略无状态化设计
- 策略预编译(如使用Java注解处理器)
- 策略缓存热点路径
- 异步策略执行
- 基于RingBuffer的无锁调度
// 高性能策略执行器示例 public class StrategyExecutor { private final Disruptor<StrategyEvent> disruptor; public StrategyExecutor() { this.disruptor = new Disruptor<>( StrategyEvent::new, 1024, DaemonThreadFactory.INSTANCE ); disruptor.handleEventsWith(this::applyStrategy); disruptor.start(); } public CompletableFuture<Result> execute(Strategy strategy, Input input) { CompletableFuture<Result> future = new CompletableFuture<>(); disruptor.publishEvent((event, seq) -> { event.setStrategy(strategy); event.setInput(input); event.setFuture(future); }); return future; } private void applyStrategy(StrategyEvent event, long seq, boolean endOfBatch) { try { Result result = event.getStrategy().execute(event.getInput()); event.getFuture().complete(result); } catch (Exception e) { event.getFuture().completeExceptionally(e); } } }10. 从策略模式到领域设计
10.1 策略模式与DDD的融合
在领域驱动设计中,策略模式可以优雅地实现领域服务:
// 领域模型中的策略应用 public class Order { private List<OrderLine> lines; private PricingStrategy pricingStrategy; public void applyPricingStrategy(PricingStrategy strategy) { this.pricingStrategy = strategy; } public BigDecimal calculateTotal() { BigDecimal total = lines.stream() .map(line -> pricingStrategy.calculatePrice(line)) .reduce(BigDecimal.ZERO, BigDecimal::add); return applyDiscounts(total); } }10.2 策略模式与Clean Architecture
在整洁架构中,策略模式常出现在Use Case层:
// 用例层的策略应用 public class PlaceOrderUseCase { private final PaymentStrategyProvider strategyProvider; public PaymentResult placeOrder(Order order, PaymentMethod method) { PaymentStrategy strategy = strategyProvider.get(method); return strategy.process(order.getTotal()); } } // 接口定义在领域层 public interface PaymentStrategy { PaymentResult process(BigDecimal amount); }10.3 策略模式与微服务设计
在微服务架构中,策略模式可以用于:
- 服务路由策略:
public interface ServiceRouter { ServiceInstance select(List<ServiceInstance> instances); } // 实现类:随机路由、轮询路由、权重路由等- 容错策略:
public interface FaultToleranceStrategy { <T> T execute(Supplier<T> supplier); } // 实现类:重试策略、熔断策略、降级策略等- 消息处理策略:
public interface MessageHandler { boolean canHandle(Message message); void handle(Message message); } // 不同消息类型对应不同处理策略11. 策略模式的现代演进
11.1 函数式编程下的策略模式
Java 8+中可以用函数接口简化策略模式:
public class FunctionalStrategy { private final Map<String, Function<Double, Double>> strategies = Map.of( "VIP", price -> price * 0.8, "NEW", price -> price * 0.9 ); public double apply(String type, double price) { Function<Double, Double> strategy = strategies.get(type); if(strategy == null) { throw new IllegalArgumentException("未知策略类型"); } return strategy.apply(price); } }11.2 策略模式与Lambda表达式
Lambda让策略实现更简洁:
public class LambdaStrategy { public static void main(String[] args) { DiscountStrategy vip = price -> price * 0.8; DiscountStrategy regular = price -> price * 0.9; System.out.println("VIP价格: " + vip.applyDiscount(100)); } } @FunctionalInterface interface DiscountStrategy { double applyDiscount(double price); }11.3 策略模式与Stream API结合
使用Stream处理策略集合:
public class StreamStrategy { public static void main(String[] args) { List<DiscountStrategy> strategies = List.of( price -> price * 0.9, price -> price > 100 ? price - 10 : price ); double finalPrice = strategies.stream() .reduce(100.0, (price, strategy) -> strategy.applyDiscount(price), (a, b) -> b); System.out.println("最终价格: " + finalPrice); } }12. 策略模式工具与框架支持
12.1 Spring中的策略实现方案
- 基于Bean注入的方案:
// 定义策略接口 public interface DataExportStrategy { String getType(); void export(Data data); } // 实现策略 @Service public class CsvExportStrategy implements DataExportStrategy { @Override public String getType() { return "CSV"; } @Override public void export(Data data) { /* CSV导出实现 */ } } @Service public class ExcelExportStrategy implements DataExportStrategy { @Override public String getType() { return "EXCEL"; } @Override public void export(Data data) { /* Excel导出实现 */ } } // 策略路由器 @Service public class ExportRouter { private final Map<String, DataExportStrategy> strategies; @Autowired public ExportRouter(List<DataExportStrategy> strategyList) { this.strategies = strategyList.stream() .collect(Collectors.toMap( DataExportStrategy::getType, Function.identity() )); } public void export(String type, Data data) { DataExportStrategy strategy = strategies.get(type); if(strategy == null) { throw new IllegalArgumentException("不支持的导出类型"); } strategy.export(data); } }- 基于Spring Boot自动配置的方案:
// 自动配置类 @Configuration public class StrategyAutoConfiguration { @Bean @ConditionalOnMissingBean public StrategyRegistry strategyRegistry(List<MyStrategy> strategies) { return new StrategyRegistry(strategies); } } // 策略接口 public interface MyStrategy { String getType(); void execute(); } // 策略注册中心 public class StrategyRegistry { private final Map<String, MyStrategy> strategies; public StrategyRegistry(List<MyStrategy> strategies) { this.strategies = strategies.stream() .collect(Collectors.toMap( MyStrategy::getType, Function.identity() )); } public MyStrategy getStrategy(String type) { return strategies.get(type); } }12.2 策略模式在JUnit中的妙用
使用策略模式实现参数化测试:
public class PricingTest { private final PricingStrategy strategy; public PricingTest(PricingStrategy strategy) { this.strategy = strategy; } @ParameterizedTest @MethodSource("strategyProvider") void testPricing(PricingStrategy strategy) { double result = strategy.calculate(100); assertTrue(result > 0); } static Stream<Arguments> strategyProvider() { return Stream.of( Arguments.of(new VipPricing()), Arguments.of(new RegularPricing()) ); } }12.3 策略模式与Lombok的结合
使用Lombok简化策略实现:
@FunctionalInterface public interface ValidationStrategy { boolean validate(String input); @RequiredArgsConstructor public static class LengthStrategy implements ValidationStrategy { private final int min; private final int max; @Override public boolean validate(String input) { return input != null && input.length() >= min && input.length() <= max; } } } // 使用示例 ValidationStrategy strategy = new ValidationStrategy.LengthStrategy(3, 10); boolean valid = strategy.validate("hello");13. 策略模式代码重构实战
13.1 重构前:传统if-else实现
public class DiscountCalculator { public double calculate(String type, double price) { if("VIP".equals(type)) { return price * 0.8; } else if("NEW".equals(type)) { return price * 0.9; } else if("FESTIVAL".equals(type)) { return price > 100 ? price - 20 : price; } else { throw new IllegalArgumentException("未知折扣类型"); } } }存在的问题:
- 违反开闭原则(修改需要改动原有代码)
- 方法职责过重(包含所有折扣逻辑)
- 难以单元测试(各种分支耦合在一起)
- 业务逻辑不清晰(折扣规则混在条件判断中)
13.2 重构步骤详解
第一步:提取策略接口
public interface DiscountStrategy { String getType(); double apply(double originalPrice); }第二步:实现具体策略类
public class VipDiscount implements DiscountStrategy { @Override public String getType() { return "VIP"; } @Override public double apply(double price) { return price * 0.8; } } public class FestivalDiscount implements DiscountStrategy { @Override public String getType() { return "FESTIVAL"; } @Override public double apply(double price) { return price > 100 ? price - 20 : price; } }第三步:创建策略上下文
public class DiscountContext { private final Map<String, DiscountStrategy> strategies; public DiscountContext(List<DiscountStrategy> strategyList) { this.strategies = strategyList.stream() .collect(Collectors.toMap( DiscountStrategy::getType, Function.identity() )); } public double calculate(String type, double price) { DiscountStrategy strategy = strategies.get(type); if(strategy == null) { throw new IllegalArgumentException("未知折扣类型"); } return strategy.apply(price); } }第四步:客户端使用
public class Client { public static void main(String[] args) { List<DiscountStrategy> strategies = List.of( new VipDiscount(), new FestivalDiscount() ); DiscountContext context = new DiscountContext(strategies); double vipPrice = context.calculate("VIP", 100); System.out.println("VIP价格: " + vipPrice); } }13.3 重构效果评估
可维护性提升:
- 新增折扣类型只需添加新策略类
- 修改现有折扣逻辑不影响其他代码
- 每个策略类职责单一
可测试性增强:
- 每个策略可以独立测试
- 上下文逻辑可以mock策略测试
- 测试用例更聚焦
业务清晰度提高: