面向对象设计六大原则是应对变化的思考工具,需权衡“何时松、何处紧”:单一职责依变更驱动拆分,开闭原则聚焦可预判扩展,接口按业务场景聚合,里氏替换重语义一致性,迪米特法则重调用安全性。

面向对象设计的六大原则不是教条,而是应对变化的思考工具。过度套用反而导致类爆炸、接口泛滥、调用链冗长——这不是设计优雅,是设计失衡。关键不在“要不要守”,而在“何时松、何处紧”。
单一职责:别为“理论上可拆”而硬拆
一个类是否该拆,看它是否真被不同角色、不同节奏、不同原因驱动修改。比如用户注册流程中,校验逻辑和数据库保存常同步演进(同一需求方、同一次迭代),强行拆成 ValidateService + SaveService 反而增加协调成本。只有当校验规则由风控团队维护、存储策略由DBA团队管理、日志格式由SRE团队定义时,才真正需要物理隔离。
- 判断信号:修改某部分逻辑时,是否总要同步改另一部分?如果是,它们大概率属于同一职责
- 落地建议:先用私有方法分组 + 清晰注释;等出现第一个独立变更点(如“短信校验下周上线,邮箱校验下月下线”),再提取为独立类
- 反模式:把每个 getter/setter、每个 if 分支都包装成一个 Service
开闭原则:开放不等于“所有地方都预留扩展点”
对扩展开放,前提是能预判扩展方向。支付模块预留“支持新渠道”是合理开闭;但提前为“未来可能支持离线支付、跨星系结算、量子签名”设计抽象层,就是空转消耗。
- 判断信号:是否有明确的新需求线索(如PM已排期、客户已签约、协议文档已签署)
- 落地建议:用策略模式 + 配置驱动,比继承更轻量;新增渠道只需加一个实现类 + 配置项,不碰核心流程
- 反模式:为每个 if-else 都定义 Strategy 接口,结果90%的实现类只被调用一次
接口隔离与依赖倒置:小接口 ≠ 好接口
接口不是越小越好,而是让使用者一眼看清契约边界。把 User 的 name、age、avatar 拆成三个独立接口,调用方得注入三个对象才能展示头像卡——这违背了“最小完整能力单元”原则。
- 判断信号:客户端是否总是一起使用这些方法?是否总在同一个上下文里调用?
- 落地建议:按业务场景聚合接口(如 UserProfileReader、UserProfileUpdater),而非按字段或技术动作切分
- 反模式:interface IUserEmail、interface IUserPhone、interface IUserAddress……最终组合出17个接口才能加载一个用户
里氏替换与迪米特法则:继承和调用深度要服务于可理解性
子类替换父类不是语法检查,而是语义承诺。如果子类重写后行为差异大到调用方必须加 instanceof 判断,那就该放弃继承,改用组合或事件通知。同样,迪米特法则不是禁止跨层调用,而是避免“为了省一行代码,让UI层直接操作DAO的内部集合”。
- 判断信号:调用方是否需要了解被调用对象的内部结构才能安全使用?是否需要读源码才能猜出返回值含义?
- 落地建议:用 DTO 封装跨层数据;用 Domain Event 替代深层回调;继承仅用于“is-a”且行为收敛的场景(如 DiscountStrategy → SeasonalDiscount)
- 反模式:AbstractUserProcessor ← UserRegisterProcessor ← WeChatUserRegisterProcessor ← WeChatMiniAppUserRegisterProcessor

















