策略接口必须用 interface 而非 abstract class,因其需支持任意类(含已有父类者)实现,确保运行时动态替换与解耦;abstract class 强制继承,破坏即插即用性。

策略接口定义时,为什么必须用 interface 而不是 abstract class
因为策略模式的核心是「运行时动态替换」,需要让不同业务逻辑实现完全解耦、互不继承。用 interface 能保证任意类(哪怕是已有父类的)都能实现它;而 abstract class 会强制继承,破坏策略的即插即用性。
常见错误:把策略基类写成 abstract class StrategyBase,结果发现订单服务类已经继承了 Service,无法再继承它——只能退回去重写成接口。
- 所有策略实现类应只依赖
Strategy接口,不感知彼此 - 接口方法不要带默认实现(Java 8+ 的
default方法容易诱使你塞共享逻辑,违背策略隔离原则) - 如果真有公共行为,抽成工具类或通过构造参数注入,别放进策略接口里
Spring 中如何自动装配一堆策略实现
靠 @Autowired 注入 List<strategy></strategy> 或 Map<string strategy></string>,Spring 会自动把所有实现该接口的 Bean 收集进来。这是最轻量、最符合 Spring 原生机制的做法。
常见错误:手动 new 实例、或用 if-else 判断类型再 cast,既难测又绕过 Spring 生命周期管理。
立即学习“Java免费学习笔记(深入)”;
- 确保每个策略实现类都加了
@Component(或子注解如@Service) - 想按名称区分策略?在实现类上加
@Qualifier("payAlipay"),然后用Map<string strategy></string>注入,key 就是 qualifier 值 - 别在策略类里直接
@Autowired其他 service——它只是个纯逻辑容器,依赖应由调用方传入或通过构造器注入
运行时选策略,if-else 和 Map 查找哪个更安全
用 Map<string strategy></string> 查找。if-else 容易漏分支、难覆盖、改起来像踩雷;Map 查找失败会抛 NullPointerException 或明确提示 key 不存在,问题暴露得早。
典型场景:支付渠道由前端传 "alipay"、"wechat" 字符串决定走哪个策略。
- 初始化 Map 时用
new HashMap(strategies),别用ImmutableMap——后续新增策略要重启应用,失去动态性 - 查找前先校验 key 是否存在:
if (!strategyMap.containsKey(channel)) { throw new IllegalArgumentException("Unsupported channel: " + channel); } - 避免用枚举做 key:枚举值硬编码在代码里,前端传错字符串就进不了 switch,但 Map 至少能兜住异常
策略类里调用外部服务,怎么避免 NPE 和超时雪崩
策略本身不该管重试、降级、熔断——那是调用方(比如订单服务)的责任。策略只负责「给定输入,返回确定输出」,否则职责混乱,单元测试没法写。
常见错误:在 doExecute() 里直接调 paymentClient.pay(),没包 try-catch,一出错整个下单流程卡死。
- 策略方法签名保持简单:
Result execute(Request request),不抛受检异常 - 外部调用统一由上层封装(比如
PaymentService),策略只接收一个已封装好的PaymentExecutor实例作为参数 - 超时时间必须由调用方控制,策略内部不做
Thread.sleep或自定义 timeout









