在Java里策略模式如何实现_JavaStrategyPattern核心解析

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

策略模式在 Java 中不是靠某个类或框架自动提供的,而是通过接口 + 多个实现类 + 上下文委托的组合方式手动构建的。它不解决“能不能用”的问题,只解决“如何让算法可替换、不修改调用方”的问题。

为什么必须定义 Strategy 接口而不是抽象类

策略的核心是「算法契约」,而非「共享逻辑」。用接口能避免继承层级污染,也方便 Lambda 表达式或匿名内部类快速实现。

  • 如果用抽象类,子类被迫继承,哪怕只用一个方法,也会带上无关的 protected 字段或模板方法
  • java.util.Comparator 是典型策略接口——compare(T, T) 是唯一契约,JDK 甚至允许写成 (a, b) -> a - b
  • 接口支持多实现(比如一个类同时实现 ValidationStrategyFormatStrategy),抽象类做不到

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 默认按类型注入,多个实现类会报错。

  • 给每个实现类加 @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,上下文就很难安全编排。