避免过度设计的关键是让设计严格服务于当前问题:有痛点才抽象,有变化才扩展;优先用if-else实现新功能,重复两处以上再抽取;仅当“修改一处影响多处”时引入多态;继承不超过两层,优先组合;参数必须显式传入,禁用默认值;通过小步重构持续演进。

避免过度设计的关键不是放弃面向对象,而是让设计严格服务于当前问题——有明确痛点才引入抽象,有真实变化才预留扩展点。
从具体问题出发,不预设未来需求
很多过度设计源于“将来可能要改”的猜测。比如刚写一个支付方法,就提前拆出 PaymentStrategy、PaymentContext、PaymentFactory 三层结构。实际应先实现一个干净的 pay(…) 方法;等真正出现微信、支付宝、余额三种支付逻辑且行为差异明显时,再提取策略接口。没有第二个实现前,策略模式就是过度设计。
- 新功能上线优先用最直接的写法(如 if-else 或 switch)
- 当同一段逻辑在两处以上重复出现,再考虑抽取共用方法或类
- 只有当“修改一处影响多处”或“新增一种类型需改多个地方”成为现实问题,才引入继承、接口或多态
控制继承深度,优先组合而非继承
继承链超过两层(A → B → C)就容易失控。子类对父类的依赖越深,修改风险越高。Java 中更推荐用字段组合 + 接口契约代替层层 extends。
- 把可变行为定义为接口(如
Serializer、RetryPolicy),通过构造函数注入 - 基类只保留稳定不变的流程骨架(如 “校验→执行→记录”),核心逻辑交由组合对象完成
- 将基类方法默认设为
final,仅开放少数protected abstract钩子(如doExecute()),防止子类随意覆盖关键步骤
参数与配置必须显式传入,不设默认值字段
类里藏着 private int timeout = 3000; 看似方便,实则埋下隐患:后续不同场景需要不同超时值时,要么加 if 判断,要么改字段语义,最终演变成“配置开关地狱”。
- 所有可变参数(超时、重试次数、序列化格式、日志级别)必须通过构造函数或 Builder 显式传入
- 不提供无参构造器;不设字段默认值;不依赖 Spring 的 @Value 注入“魔法值”
- 单元测试中能一眼看清每个实例的配置差异,而不是翻源码猜行为
用重构代替预设架构
设计不是一次性工程,而是一个持续演进的过程。与其花三天画 UML 图规划十年扩展性,不如一天写出可运行代码,再用两天小步重构。
- 每次合并前问自己:这段代码现在是否难读?是否难测?是否难改?
- 发现 if 分支变多 → 提取策略接口
- 发现构造参数越来越多 → 引入 Builder 模式
- 发现多个类共享状态和行为 → 抽象为领域模型或服务类
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











