首页/开发/代码质量与评审速查/SOLID 落地:用策略模式实现开闭
设计原则与模式62 条

SOLID 落地:用策略模式实现开闭

把「新增类型要改调用方」改造为「新增类型只加实现」:以折扣计算为例,策略接口 + 工厂/注册表把分支集中到组装点,业务主流程保持不变。

用策略模式实现开闭

把新增类型要改调用方改造成新增类型只加实现。以折扣计算为例:策略接口定义统一的计算方法,每个客户等级各写一个实现,工厂或注册表负责装配;业务主流程不再出现按等级分支,扩展时只往注册表加一行。

基本信息

改造对象按客户等级分支计算折扣的调用点
落地手法策略接口 + 实现类 + 注册表装配
验收标准新增等级不改主流程
关键约束装配点要唯一
相关原则开闭原则、单一职责

典型使用场景

  • 折扣、运费、佣金等按类型变化的计算规则
  • 支付渠道的费率与校验差异
  • 导入导出格式的解析与序列化
  • 通知渠道的发送策略
  • 校验规则的组合与开关

策略与装配

策略与装配
interface DiscountPolicy { Money apply(Order order); }
class VipPolicy implements DiscountPolicy { ... }
class NewUserPolicy implements DiscountPolicy { ... }

// 装配点集中在一处,新增等级只改这里
Map<Tier, DiscountPolicy> registry = Map.of(
    Tier.VIP, new VipPolicy(),
    Tier.NEW, new NewUserPolicy());

落地要点

要点做法说明
接口约定明确输入输出与异常语义实现之间才可替换
装配集中工厂或注册表唯一避免出现新的修改面
未知类型显式失败而不是兜底防止静默走到错误策略
判断改造是否成功,看新增一种类型的改动范围:如果只改装配点、加一个实现类,主流程一行不动,扩展点就真的开出来了。

不适用的信号

  • 分支只有两三个且长期稳定,改动频率极低
  • 各分支逻辑差异很小,只是参数取值不同
  • 所谓扩展点由配置文件驱动,但实际没人会改
  • 接口语义尚未稳定,现在加抽象只会增加返工成本
注册表分散在多处装配,等于把原来的分支判断换成了新的修改面:新增类型仍要改好几个地方,还多了一层间接。
落地后要保留一条显式失败路径:类型未匹配时直接报错,而不是回落到某个默认策略,否则配置错误会静默生效。

易错点

  • 注册表分散在多处:装配点不唯一,又出现新的修改面
  • 策略接口只有方法签名:缺少输入输出与异常约定,实现水平参差
  • 未知类型静默兜底:新增类型漏配时走到默认策略,错误悄无声息
  • 为两个稳定分支搭策略体系:抽象成本高于收益,调用链多出一层

数据来源与参考

  • 《重构》第 2 版(Replace Conditional with Polymorphism)与 OCP 结合实践
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌