一、先说动机:为什么需要这些原则?
软件的主旋律是“变化”。每一次需求/技术/合规变化,都会在代码图上引发“涟漪效应”(改动一处牵扯多处)。六大原则就是行业长期实践中对“降低涟漪成本”的经验压缩,其共识目标是:
-
降低修改半径(局部化变化)
-
降低依赖强度(把握依赖方向)
-
保持替换安全(多态不踩雷)
-
控制接口边界(暴露越少越好)
-
提升可测试性与可演进性
换句话说:设计 = 管理变化,六大原则分别从“职责、扩展、替换、依赖、接口、协作”六个轴来约束变化的代价。
二、六个轴分别解决什么问题?
| 原则 | 关注对象 | 解决的核心问题 | 一句话检验 |
|---|---|---|---|
| SRP 单一职责 | 模块/类 | 让变化有且仅有一个原因触发它 | “这个类改动的理由能不能再分?” |
| OCP 开闭 | 扩展点 | 新需求尽量新增代码而非改旧码 | “这类变化能用新增实现吗?” |
| LSP 里氏替换 | 类型层次 | 子类型可替换父类型且不破坏正确性 | “把子类实参换成父类,行为还对吗?” |
| DIP 依赖倒置 | 依赖方向 | 高层不依赖低层细节,共同依赖抽象 | “稳定层是否只依赖抽象/接口?” |
| ISP 接口隔离 | API 形状 | 客户只看到/实现自己需要的方法 | “这个接口对某个客户是否‘太胖’?” |
| LoD 迪米特法则 | 协作半径 | 降低对象间了解度,减少链式耦合 | “我是否在跟‘朋友的朋友’说话?” |
直觉图:
-
SRP管“内聚”;
-
OCP/DIP/ISP共同管“扩展与依赖方向”;
-
LSP是“多态正确性”的约束;
-
LoD管“耦合半径”(信息隐藏)。
三、它们之间不是平行孤岛,而是“内在联动”
-
OCP 的落地往往依赖 DIP(抽象扩展点)+ ISP(细粒度接口)+ LSP(替换安全)。
-
SRP提升内聚,间接降低因修改引起的连锁反应,为 OCP 创造土壤。
-
LoD限制“对象图的触达距离”,避免“修改 A 却牵连 A 的朋友们”,与 SRP 一起控制耦合扩散。
因此,“正好这六个”的原因是:它们覆盖了从类型正确性到依赖方向、到接口边界、到协作半径的关键面,彼此配合构成一个相对闭合的“变化成本最小化”体系。
四、用小例子看每条原则的“痛点—解法—收益”
-
SRP:报表服务既算账又发邮件 → 拆成 ReportGenerator 与 Notifier。
- 变化:改邮件模板不再触动计算逻辑。
-
OCP:新增一种“积分优惠” → 通过注册新的 DiscountPolicy 实现,而非改 switch。
-
LSP:Square 继承 Rectangle 导致 setWidth 破坏长方形不变量 → 抽象为 Shape,分别实现面积逻辑,避免错误替换。
-
DIP:高层模块依赖 PaymentGateway 接口,具体用 Stripe/PayPal 由装配期决定。
-
ISP:把“超大通用 DAO 接口”按读/写/分页拆成小接口,调用方只依赖所需能力。
-
LoD:拒绝 order.getCustomer().getAddress().getCity() 的链式穿透,改成 order.city() 由内部转发(或一次性 DTO)。
五、为什么不是更多或更少?
- 少了不够用:只讲 SOLID(SRP/OCP/LSP/ISP/DIP)还少一个“协作半径”的视角,于是补上 LoD,能更好控制对象图的传播耦合。
- 多了冗余/重叠:再继续加(如“合成复用原则”CARP),常与前述在工程实践中功能重叠(组合优先本质也服务于 SRP/OCP/DIP/LoD)。六条已能覆盖主流变化维度,保持“简洁而不简单”。
六、应用取舍:别教条,讲“触发器”
-
**何时启用/加强?**出现以下 smell 就该引入对应原则的重构:
- “上帝类/巨类” → SRP 拆分;
- 新需求总要改旧类 → 抽象扩展点(OCP + DIP + ISP);
- 子类替换父类出错/需要写 instanceof → LSP 改抽象或去继承用组合;
- 方法调用出现“火车式点号”→ LoD 封装转发;
-
何时克制?过度抽象、接口碎片化、为未来而设计都会增加即时复杂度。经验法则:先直白实现 + 用测试保护,当出现第二次相似变化时再抽象成可扩展形。
七、落地清单(面向团队评审/自检)
- 每个类是否能一句话说清“唯一职责”?(SRP)
- 新增一种策略/适配器时是否无需改旧类?(OCP)
- 任何使用父类型的地方换子类型是否毫无意外?(LSP)
- 依赖是否都指向接口/抽象,具体实现由装配期决定?(DIP)
- 接口是否细到“客户只依赖需要的方法”?(ISP)
- 代码中是否存在“朋友的朋友”式长链访问?(LoD)
一句话总结:
六大原则是围绕“最小化变化成本”从六个正交维度提炼出的行业共识:用 SRP 提高内聚、以 OCP/DIP/ISP 打造可扩展与正确的依赖方向、凭 LSP 保证多态替换安全、再用 LoD 控制协作半径。它们彼此支撑,构成一个能让系统易改、易测、易演进的最小充分集合。