核心是将变化逻辑外置为可插拔策略,原有类仅存数据并暴露标准接口;通过定义通用接口(如paymentstrategy)、实现策略类、依赖注入动态切换,使数据类保持“哑”容器本质,严格遵循开闭原则。

核心是把“变”的逻辑抽出来,让原有类只做不变的事——它只存数据、暴露标准接口,所有业务规则由外部可插拔的组件承担。
识别并抽象稳定契约
先找出哪些行为会随需求变化(比如金额舍入、支付方式、校验规则),再为它们定义统一接口。这个接口就是不变的契约,例如 PaymentStrategy、ValidationRule 或 AmountRoundingStrategy。接口方法要足够通用,不绑定具体场景。
- 避免在接口里塞业务字段(如
isForFinance),那是把变化又塞回了抽象层 - 方法签名尽量简洁,比如
apply(BigDecimal value),而不是apply(BigDecimal value, String context, boolean force) - 接口命名体现职责,而非实现,如用 Formatter 而非 JsonFormatter
用策略模式组织扩展点
每个新业务规则写成一个独立类,实现上述接口。老代码完全不感知这些类的存在,只依赖接口类型。
- 新增微信支付?写个 WechatPayment 类,实现 PaymentStrategy
- 加税务舍入?写个 TaxRounding 类,实现 AmountRoundingStrategy
- 所有新类都和旧类物理隔离,编译、测试、部署互不影响
通过依赖注入或策略注册动态接入
运行时决定用哪个实现,而不是硬编码在业务逻辑里。
- Spring 中用
@Service("wechat")注册,再用@Qualifier("wechat")注入 - .NET Core 里注册为
ISingleton<paymentstrategy></paymentstrategy>,按名称解析 - 或自建策略注册表:
StrategyRegistry.get("payment.wechat"),启动时自动扫描加载 - 配置文件控制切换,比如 YAML 里改
payment.strategy: alipay就生效
守住变量的“哑”本质
数据类(如 Order、Amount)不该有 if-else 分支,也不该持有 flag 字段。
- 删掉
order.isForFinance这类字段,它让变量承担语义判断 - 不要在
Amount.round()里写 switch,而是调用注入的roundingStrategy.round(this.value) - 让变量真正成为“容器”,行为全部外移——这是 OCP 落地最常被忽略的一环










