为什么需要设计原则?
降低耦合
当类 A 直接依赖于类 B 的内部实现,任何对 B 的微小改动都可能引发 A 的连锁变更。通过设计原则,我们可以让各模块之间的依赖关系朝 抽象、接口 方向转移,减少因实现细节改动带来的冲击面。提高内聚
将职责高度相关的逻辑聚拢到单个组件或类中,有利于定位问题和重构。当一个类只做一件事,且只做这一件事时,它就更容易理解、测试、扩展。支持可扩展
在满足 开闭原则 的情况下,我们可以新增功能(扩展)而不修改已有代码(闭合),最大程度避免回归缺陷。增强可测试
通过 依赖倒置 和 接口隔离,可以轻松替换外部依赖为 Mock,在单元测试中只聚焦业务逻辑本身。
七大面向对象设计原则一览
| 序号 | 原则 | 英文缩写 | 核心关注 |
|---|---|---|---|
| 1 | 单一职责原则 | SRP | 责任分离:每个类/模块只承担一种原因引起的变化,通过高内聚降低噪声 |
| 2 | 开闭原则 | OCP | 可扩展性:用抽象(接口/基类)和多态,实现新增行为无需修改已有代码 |
| 3 | 里氏替换原则 | LSP | 行为契约:子类型在语义、前置/后置条件和不变式上必须与父类型保持兼容 |
| 4 | 接口隔离原则 | ISP | 细粒度接口:为不同客户角色定制最小功能集,避免“胖接口”与无用依赖 |
| 5 | 依赖倒置原则 | DIP | 依赖抽象:高层模块与底层模块都依赖于抽象,以接口为壁,减少实现耦合 |
| 6 | 组合复用原则 | CRP | 组合优先:通过对象组合/委托实现功能复用,替代脆弱的类继承层级 |
| 7 | 最少知识原则 | LKP | 最少暴露:对象只与直接朋友通信,限制链式依赖,降低模块间耦合 |
七大原则的相互关系
SRP → OCP → LSP → ISP → DIP 构成 SOLID 五原则,是保持类层面良好设计的“连环锁”。
CRP(Composite Reuse Principle)与 LKP(Least Knowledge Principle)补齐了 SOLID 在继承与对象交互方面的短板。
DIP 是 SOLID 中的“核心”,它保证了上层模块不会因下层模块变化而受到影响;而 LKP 则进一步约束了模块间的通信边界。
flowchart LR SRP["单一职责 (SRP)"] OCP["开闭原则 (OCP)"] LSP["里氏替换 (LSP)"] ISP["接口隔离 (ISP)"] DIP["依赖倒置 (DIP)"] CRP["组合复用 (CRP)"] LoD["最少知识 (LKP)"] SRP --> OCP OCP --> LSP LSP --> ISP ISP --> DIP DIP --> CRP DIP --> LKP CRP --> LKP
简单示例:如何违反 SRP 与 DIP
// 反例:LogAndSaveOrder 既负责订单校验,又负责日志记录和持久化 public class OrderProcessor { public void Process(Order o) { if (!Validate(o)) throw new Exception("Invalid"); Log($"Processing {o.Id}"); SaveToDatabase(o); } // … Validate, Log, SaveToDatabase 均在同一类中 } // 改进:单一职责 + 依赖倒置 public interface ILogger { void Log(string msg); } public interface IOrderRepository { void Save(Order o); } public class OrderProcessor { private readonly ILogger _logger; private readonly IOrderRepository _repo; public OrderProcessor(ILogger logger, IOrderRepository repo) { _logger = logger; _repo = repo; } public void Process(Order o) { if (!Validate(o)) throw new Exception("Invalid"); _logger.Log($"Processing {o.Id}"); _repo.Save(o); } bool Validate(Order o) { … } }SRP:OrderProcessor 只负责“流程控制”职责,ILogger 和 IOrderRepository 分别负责日志和持久化。
DIP:高层 OrderProcessor 依赖抽象 ILogger、IOrderRepository,无需关心具体实现。