开闭原则的核心是通过抽象隔离变化点,新增功能只需添加新类而不修改旧代码。例如用PaymentStrategy接口定义支付契约,AlipayStrategy等具体类实现不同支付方式,OrderService依赖接口并运行时注入,扩展时仅新增实现类即可。

在 Java 面向对象设计中应用开闭原则,核心是让类或模块能新增功能而不改旧代码。关键不在于“完全不能动”,而在于把变化点隔离出来,用抽象兜住不变的部分,让新行为通过新增类来承载。
用接口或抽象类定义稳定契约
把会变的行为(比如计算方式、数据来源、渲染逻辑)抽成接口或抽象类,作为扩展的入口。具体实现类只负责各自逻辑,互不影响。
- 例如定义 PaymentStrategy 接口,含
pay(double amount)方法; - 再写 AlipayStrategy、WechatPayStrategy、CreditCardStrategy 各自实现;
- 主业务类(如 OrderService)只依赖 PaymentStrategy,运行时注入具体策略——加新支付方式,只需新增一个实现类,不碰原有任何代码。
避免条件分支硬编码变化
当看到 if (type.equals("A")) { ... } else if (type.equals("B")) { ... } 这类判断时,往往就是违反开闭原则的信号。这类逻辑容易随需求增长而不断修改同一段代码。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 应改为工厂 + 策略:用 Map<String, Strategy> 或简单工厂返回对应策略实例;
- 新增类型时,只往工厂里注册新策略,不改判断逻辑本身;
- 若类型来自配置或数据库,甚至可做到零代码发布新行为。
依赖抽象,而非具体实现
方法参数、成员变量、返回值尽量使用接口或抽象类类型。这样上层代码不会因底层实现更换而失效。
立即学习“Java免费学习笔记(深入)”;
- 比如日志模块定义 Logger 接口,业务类持有
private final Logger logger; - 开发时用 ConsoleLogger,上线切到 FileLogger 或 SlackLogger,只需改构造注入,业务类本身无需重编译;
- Spring 的
@Autowired注入正是基于这一思路,天然支持开闭。
配合设计模式落地
单靠抽象还不够,需结合成熟模式组织扩展结构:
- 策略模式:封装算法族,运行时切换(如不同排序、校验、折扣规则);
- 模板方法:父类定骨架,子类覆写钩子方法(如报表生成流程固定,但数据源和格式可替换);
- 装饰器模式:动态叠加功能(如给 InputStream 加缓存、加密、压缩,每种装饰器独立,组合自由)。

















