策略模式需通过接口+多实现类+上下文委托手动构建,核心是定义算法契约而非共享逻辑,故用接口更优;Context推荐构造注入并校验非空;Spring中可用@Qualifier或Map注入;各策略实现须保持边界一致性。

策略模式在 Java 中不是靠某个类或框架自动提供的,而是通过接口 + 多个实现类 + 上下文委托的组合方式手动构建的。它不解决“能不能用”的问题,只解决“如何让算法可替换、不修改调用方”的问题。
为什么必须定义 Strategy 接口而不是抽象类
策略的核心是「算法契约」,而非「共享逻辑」。用接口能避免继承层级污染,也方便 Lambda 表达式或匿名内部类快速实现。
- 如果用抽象类,子类被迫继承,哪怕只用一个方法,也会带上无关的
protected字段或模板方法 -
java.util.Comparator是典型策略接口——compare(T, T)是唯一契约,JDK 甚至允许写成(a, b) -> a - b - 接口支持多实现(比如一个类同时实现
ValidationStrategy和FormatStrategy),抽象类做不到
Context 类里要不要持有 Strategy 的 setter 方法
要,但得看场景。硬编码 new 实例会锁死策略,而完全暴露 setter 又可能被误设为 null。
- 构造时传入(推荐):
public class DiscountContext { private final DiscountStrategy strategy; public DiscountContext(DiscountStrategy strategy) { this.strategy = Objects.requireNonNull(strategy); } } - 运行时切换需加 null 检查:
public void setStrategy(DiscountStrategy strategy) { this.strategy = Objects.requireNonNull(strategy, "strategy must not be null"); } - 不要用字段直接 public——破坏封装,且无法做校验
Spring 环境下怎么避免手动 new 策略实现类
靠 @Qualifier + 接口注入,但要注意 Spring 默认按类型注入,多个实现类会报错。
立即学习“Java免费学习笔记(深入)”;
- 给每个实现类加
@Component("vipDiscount")、@Component("seasonalDiscount") - 上下文类用
@Autowired @Qualifier("vipDiscount") private DiscountStrategy strategy; - 更灵活的方式是注入
Map,key 是 bean 名,运行时按业务规则选:@Autowired private Map
strategies; public BigDecimal calculate(String type, BigDecimal amount) { return strategies.getOrDefault(type, new DefaultDiscount()).apply(amount); }
最容易被忽略的是策略的「边界一致性」:所有实现类对同一输入的输出类型、空值处理、异常抛出约定必须统一。比如一个 parse() 策略返回 null,另一个抛 ParseException,上下文就很难安全编排。










