策略模式本身不能自动消除if-else,真正起效的是“策略+工厂+预注册map”组合;单纯接口实现仍需if/switch选策略,而工厂通过启动时注册map实现o(1)精准获取,新增策略仅需加类并注册,不改原有逻辑。

直接说结论:策略模式本身不能「自动消除」if-else,它只是把判断逻辑从主流程里移出去;真正起作用的是「策略 + 工厂 + 预注册 Map」这一组合,否则你只是把 if 换成了 for 或 stream().filter(),照样难维护。
为什么单纯用 Strategy 接口还是绕不开 if-else
很多人第一步就定义一个 PaymentStrategy 接口,再写 AlipayStrategy、WechatStrategy,但调用时卡在「怎么拿到正确的策略实例」这一步——结果写出这种代码:
if ("alipay".equals(payType)) {
strategy = new AlipayStrategy();
} else if ("wechat".equals(payType)) {
strategy = new WechatStrategy();
}
这根本没解决问题,只是把分支挪了个位置。关键缺失是:没有统一的策略获取入口,也没有运行时动态绑定能力。
- Spring 中靠
@Autowired List<paymentstrategy></paymentstrategy>+stream().filter(...)查找,但每次调用都遍历列表,性能差,且无法按 key 精准命中 - 手写
switch或if映射,等于回到原点 - 没做参数校验或兜底策略,
payType传错就NullPointerException
必须搭配工厂类 + 静态 Map 注册
工厂不是可选模块,是策略落地的基础设施。核心就三点:
- 所有策略实现类在启动时(如 Spring
@PostConstruct)注册进一个Map<string paymentstrategy></string> - 工厂提供
getStrategy(String type)方法,内部只做map.getOrDefault(type, defaultStrategy) - 策略类自己不持有类型标识,类型由注册时的 key 决定(比如
map.put("alipay", new AlipayStrategy()))
这样主流程才真正变成一行:
paymentFactory.getStrategy(payType).process(orderId, amount);
新增支付方式?加个新类 + 在工厂注册行,不碰任何已有分支逻辑。
Spring 环境下避免手动注册的坑
别依赖 List<t></t> 自动注入后遍历匹配——它既慢又模糊。更稳妥的做法是用 Spring 的 @Qualifier 或自定义注解驱动注册:
- 给每个策略类加
@Component("alipayStrategy"),工厂里用applicationContext.getBean("alipayStrategy"),但 key 硬编码易出错 - 推荐用自定义注解(如
@PayType("alipay")),配合ApplicationContextAware扫描所有带该注解的 Bean 并塞进 Map - 注意 Bean 初始化顺序:工厂类必须等所有策略 Bean 加载完才能执行注册,否则 Map 是空的
注册时机错,getStrategy() 永远返回 null,而这个错误往往在线上压测时才暴露。
策略类内部仍可能藏 if-else,得盯住
策略模式只解决「选哪个策略」的问题,不解决「策略内部怎么写」。常见翻车点:
-
ExcelExporter.export()里又根据订单状态写一堆if (status == PAID) {...} else if (status == REFUNDED) {...} - 把本该拆成子策略的逻辑(如导出模板渲染、数据脱敏、文件压缩)全塞在一个方法里
- 策略类承担了不该有的职责:比如既要处理业务规则,又要拼 SQL,还要发 MQ
这时候得继续往下拆:导出模板用模板策略,脱敏用脱敏策略,压缩用压缩策略——策略可以嵌套,但每层只负责一件事。
最常被忽略的是「策略边界」:一个策略类到底该管多大范围?答案是——只要它内部开始出现两个以上不同维度的条件判断(比如同时看 status 和 region),就说明它该拆了。










