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











