关于策略模式在实际业务中的落地,我之前在订单系统开发里,针对 “取消订单” 这个场景做过具体实现.
当时我们遇到的核心问题是:订单状态特别多,从待支付、已支付到派发中、配送中,光状态就有七八种;而且用户类型也分普通用户、运营人员等,不同身份能取消的订单类型不一样,取消逻辑更是千差万别。比如普通用户在 “待支付” 状态取消,只要直接改订单状态、释放库存就行;但如果是 “派发中” 取消,不仅要改状态,还得通知骑手终止配送,甚至要触发退款审核 —— 要是把这些逻辑全堆在一个 Service 里,代码得几百行,后续改一个场景的逻辑都怕影响其他地方,拓展性也差。
所以当时我们就选了策略模式来解耦,结构如图:
核心思路是把 “不同场景的取消逻辑” 拆成独立的策略,具体分了三步实现:
第一步是定义策略接口。我们叫它OrderCancelStrategy,里面就一个核心方法cancel,参数得包含关键决策信息:用户类型(比如 1 代表普通用户、2 代表 运营人员)、订单状态(像 NO_PAY 待支付、DISPATCHING 派发中这种枚举),还有取消原因、订单 ID 这些业务数据。这样所有取消逻辑都得遵循这个接口规范,保证统一性。
第二步是写具体的策略实现类。每个类对应一个 “用户类型 + 订单状态” 的组合,比如普通用户取消待支付订单,就建一个NormalUserNoPayCancelStrategy。关键是我们用 Spring 的@Component注解给这些 bean 命名,规则就是 “用户类型:订单状态”,比如@Component("1:NO_PAY"),这样后面能直接通过这个 key 找到对应的策略。每个类里就只写自己场景的逻辑,比如 “1:NO_PAY” 的类里,就是更新订单状态为 “已取消”,调用库存服务释放商品;而 “1:DISPATCHING” 的类里,除了改状态,还会调用骑手调度系统发终止通知,再触发退款流程 —— 每个策略类职责特别单一,改起来也放心。
第三步是做策略环境类,也就是OrderCancelContext,负责管理和调度策略。这里我们用了 Spring 的特性:启动时通过SpringUtil把所有实现了OrderCancelStrategy接口的 bean 全扫出来,存到一个HashMap<String, OrderCancelStrategy>里,key 就是前面定义的 “用户类型:订单状态”。然后环境类里写一个executeCancel方法,接收前端传的订单信息(包含用户类型、订单状态),先拼出 key,从 HashMap 里拿到对应的策略,再调用策略的cancel方法执行逻辑。
这样设计下来,业务端用的时候特别简单:不管是 APP 端、PC 端还是后台管理系统,只要注入OrderCancelContext,传一下订单和用户的核心参数,环境类会自动匹配到正确的策略。比如新增一个 “VIP 用户取消已支付未派发订单” 的场景,不用改任何旧代码,直接新建一个策略类,加@Component("2:PAID_NO_DISPATCH"),写好逻辑就行;要是待支付订单的取消逻辑要加个日志记录,也只改 “1:NO_PAY” 那个类,完全不影响其他场景。
本质上就是通过策略模式,把 “做什么”(取消订单)和 “怎么做”(不同场景的具体逻辑)分离开,既解耦了代码,又提高了拓展性和复用性 —— 后来我们系统加了十几种取消场景,都是这么快速迭代的,没出过硬编码带来的问题。