开闭原则要求不修改已有代码而扩展行为,关键在于将变量的行为(如舍入、校验)抽象为可插拔策略接口,由外部实现类承担变化,变量仅作为数据容器;新增策略只需实现接口并注册,无需改动原有类。

开闭原则(OCP)不是“不写代码”,而是“不改已有代码”——扩展变量功能的关键,在于把变量的**行为变化**抽离成可插拔的结构,而不是让变量本身承载所有逻辑分支。
把变量背后的逻辑抽象成接口或基类
变量本身通常只是数据容器,真正需要扩展的是它参与的**行为**(比如计算、校验、序列化、格式化)。所以第一步是识别这个行为的共性,定义稳定契约。
- 例如一个订单金额变量 amount,不同场景要按不同规则四舍五入:财务结算用银行家舍入,前端展示用普通舍入,风控计算用向上取整。这些不是 amount 该管的事,而是“金额处理策略”该管的事。
- 定义接口 AmountRoundingStrategy,声明 round(decimal value) 方法;
- 各策略实现为独立类:BankerRounding、DisplayRounding、CeilingRounding;
- 业务类中,amount 不再直接调用 Math.Round(),而是持有一个 AmountRoundingStrategy 实例。
运行时动态切换策略,无需改动调用方
变量功能的“扩展”,本质是行为的替换。只要上层只依赖抽象,新增策略就完全透明。
- 客户端代码像这样使用:order.getAmount().roundedBy(strategy).toBigDecimal();
- 新添一种“税务专用舍入”,只需新增一个 TaxRounding 类并实现接口;
- 配置或工厂决定注入哪个策略实例,原有 order 类、amount 类、业务服务类一行代码都不用动;
- 连单元测试也只需为新策略单独覆盖,不影响旧用例。
避免把变量变成“万能开关”
常见反模式是给变量加一堆 flag 字段(如 isForFinance、isForDisplay),再在方法里堆 if-else 判断——这等于把扩展点硬编码进变量内部,彻底违背 OCP。
- flag 越多,逻辑越耦合,每次加新用途都要改变量类和所有用到它的地方;
- OCP 要求:变量保持“哑”——它只存值、暴露标准操作(get/set/toString 等),所有语义性行为外移;
- 真正变化的部分(如舍入、单位换算、精度控制)必须由外部策略对象承担。
配合依赖注入或策略注册表,让扩展真正落地
光有接口不够,得有机制让新策略能被发现和使用。
- 在 Spring 或 .NET Core 中,把策略实现类注册为服务,按名称或上下文自动解析;
- 或维护一个 StrategyRegistry
,启动时扫描并注册所有实现; - 业务代码通过 key(如 "finance")获取策略,新增策略只需注册+配置,不碰任何已有类。










