用策略模式实现开闭
把新增类型要改调用方改造成新增类型只加实现。以折扣计算为例:策略接口定义统一的计算方法,每个客户等级各写一个实现,工厂或注册表负责装配;业务主流程不再出现按等级分支,扩展时只往注册表加一行。
基本信息
| 改造对象 | 按客户等级分支计算折扣的调用点 |
|---|---|
| 落地手法 | 策略接口 + 实现类 + 注册表装配 |
| 验收标准 | 新增等级不改主流程 |
| 关键约束 | 装配点要唯一 |
| 相关原则 | 开闭原则、单一职责 |
典型使用场景
- 折扣、运费、佣金等按类型变化的计算规则
- 支付渠道的费率与校验差异
- 导入导出格式的解析与序列化
- 通知渠道的发送策略
- 校验规则的组合与开关
策略与装配
策略与装配
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());落地要点
| 要点 | 做法 | 说明 |
|---|---|---|
| 接口约定 | 明确输入输出与异常语义 | 实现之间才可替换 |
| 装配集中 | 工厂或注册表唯一 | 避免出现新的修改面 |
| 未知类型 | 显式失败而不是兜底 | 防止静默走到错误策略 |
判断改造是否成功,看新增一种类型的改动范围:如果只改装配点、加一个实现类,主流程一行不动,扩展点就真的开出来了。
不适用的信号
- 分支只有两三个且长期稳定,改动频率极低
- 各分支逻辑差异很小,只是参数取值不同
- 所谓扩展点由配置文件驱动,但实际没人会改
- 接口语义尚未稳定,现在加抽象只会增加返工成本
注册表分散在多处装配,等于把原来的分支判断换成了新的修改面:新增类型仍要改好几个地方,还多了一层间接。
落地后要保留一条显式失败路径:类型未匹配时直接报错,而不是回落到某个默认策略,否则配置错误会静默生效。