策略模式核心是将“不同条件对应不同行为”抽离为可扩展、可替换、可测试的对象结构,而非单纯去除if-else;需识别行为差异点、封装高内聚分支、用枚举或spring bean名解耦选择,并保留必要守卫逻辑。

把 if-else 拆成策略模式,核心不是“去掉条件判断”,而是把“不同条件对应不同行为”这件事,从硬编码逻辑里抽出来,变成可扩展、可替换、可测试的对象结构。
识别可提取的业务规则分支
先别急着写接口,先看 if-else 里真正变化的是什么:是执行动作(比如发送邮件、发短信、推站内信),还是计算逻辑(比如折扣计算、风控校验),或是数据组装方式。只要分支间行为差异明显、未来可能新增或修改,就值得单独封装。
- 每个分支体里,只保留和该场景强相关的代码,剥离公共初始化、日志、异常包装等通用逻辑
- 避免把简单枚举值判断(如
if (type == 1))直接映射成策略——要判断的是“行为语义”,不是“数字编号” - 如果分支里还嵌套了 if-else,说明这个策略本身还没内聚,需要再下沉一层
定义策略接口与具体实现
接口方法名要体现业务意图,比如 applyDiscount()、notifyUser(),而不是泛泛的 execute()。参数尽量用领域对象(如 Order、NotificationContext),少用原始类型或 Map。
- 策略类保持无状态,不依赖外部上下文变量(如 Spring 的
@Service注入需谨慎,优先用构造器传参) - 实现类命名带业务含义,如
SummerPromotionStrategy、SmsNotificationStrategy,别叫StrategyImpl1 - 策略内部不做跨服务调用兜底(比如发短信失败自动切邮件),那是策略组合器或门面层的事
用工厂或注册表解耦策略选择
别在调用处 new 策略实例,也别用一堆 if-else 去 new 不同实现——这等于换汤不换药。推荐两种轻量方式:
-
枚举驱动工厂:定义枚举含 strategyClass 字段,通过
type.getStrategy().handle(context)获取并执行 -
Spring Bean 名称注册:所有策略实现类加
@Component("smsNotifyStrategy"),运行时通过applicationContext.getBean(type + "Strategy")拿 - 避免用反射根据字符串加载类——调试困难、IDE 无法跳转、编译期无检查
保留必要的守卫逻辑
策略模式不等于消灭所有 if。入口处仍需做基础校验(如参数非空、状态合法),这些不属于策略范畴,留在调用方更清晰。
- 策略内部只处理“已确认适用本策略”的情形,不负责判断是否该用自己
- 多个策略可能同时满足条件?那就引入策略链(Chain of Responsibility)或优先级排序机制,而不是塞进一个策略里 if-else
- 兜底策略(fallback)可以存在,但要显式声明,比如
DefaultDiscountStrategy,而非用 else 分支隐藏逻辑
重构不是一步到位,先提取最稳定、变更频率最低的分支,再逐步迁移。策略多了之后,配合单元测试覆盖各实现,比测一长串 if-else 容易得多。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











