我将用简洁易懂的方式介绍面向对象设计的七大核心原则(SOLID + 合成复用/迪米特法则),通过定义 + 实际案例 + 代码对比帮助理解它们的核心思想。
1. 单一职责原则 (SRP - Single Responsibility Principle)
定义:一个类只应有一个引起它变化的原因
核心思想:高内聚、低耦合
违反案例:
1 2 3 4 5
| class OrderService { public void createOrder() { } public void sendEmail() { } }
|
正确实现:
1 2 3 4 5 6 7 8
| class OrderService { public void createOrder() { } }
class EmailService { public void sendEmail() { } }
|
实际意义:修改邮件发送方式时,不会影响订单核心逻辑
2. 开闭原则 (OCP - Open-Closed Principle)
定义:软件实体应对扩展开放,对修改关闭
核心思想:通过抽象和继承/组合实现扩展
违反案例:
1 2 3 4 5 6 7 8
| class DiscountCalculator { public double calculate(String type) { if ("VIP".equals(type)) return 0.8; else if ("NEW_USER".equals(type)) return 0.9; } }
|
正确实现:
1 2 3 4 5 6 7 8 9 10 11 12 13
| interface DiscountStrategy { double applyDiscount(); }
class VIPDiscount implements DiscountStrategy { public double applyDiscount() { return 0.8; } }
class FestivalDiscount implements DiscountStrategy { public double applyDiscount() { return 0.7; } }
|
实际意义:系统扩展时无需修改已有稳定代码,降低风险
3. 里氏替换原则 (LSP - Liskov Substitution Principle)
定义:子类必须能够替换父类且不破坏程序逻辑
解释: 任何基类可以出现的地方,子类一定可以出现。里氏替换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏替换原则是对实现抽象化的具体步骤的规范。
核心思想:继承关系应确保行为兼容性
违反案例:
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Rectangle { protected int width, height; public void setWidth(int w) { width = w; } public void setHeight(int h) { height = h; } }
class Square extends Rectangle { public void setWidth(int w) { width = w; height = w; } }
|
正确实现:
1 2 3 4 5 6 7 8
| interface Shape { double getArea(); }
class Rectangle implements Shape { }
class Square implements Shape { }
|
实际意义:避免因继承导致不可预知的错误
4. 接口隔离原则 (ISP - Interface Segregation Principle)
定义:客户端不应被迫依赖它不使用的接口
核心思想:接口粒度细化,避免“胖接口”,使用多个隔离的接口,比使用单个接口要好
违反案例:
1 2 3 4 5 6 7 8 9 10 11 12
| interface Worker { void work(); void eat(); void sleep(); }
class Robot implements Worker { void work() { } void eat() { throw new UnsupportedOperationException(); } }
|
正确实现:
1 2 3 4 5 6 7 8 9 10 11
| interface Workable { void work(); }
interface Eatable { void eat(); }
class Human implements Workable, Eatable { } class Robot implements Workable { }
|
实际意义:减少不必要的依赖,提高系统灵活性
5. 依赖倒置原则 (DIP - Dependency Inversion Principle)
定义:高层模块不应依赖低层模块,二者都应依赖抽象(开闭原则的基础)
核心思想:面向接口编程,解耦模块关系
违反案例:
1 2 3 4 5 6 7
| class ReportService { private MySQLDatabase db; public void generateReport() { db.query("SELECT ..."); } }
|
正确实现:
1 2 3 4 5 6 7 8 9 10 11 12 13
| interface Database { Result query(String sql); }
class ReportService { private Database db; public ReportService(Database db) { this.db = db; } }
class MySQLDatabase implements Database { } class MongoDB implements Database { }
|
实际意义:提升代码可测试性和可维护性
6. 合成复用原则 (CRP - Composite Reuse Principle)
定义:优先使用对象组合,而不是继承来达到复用目的
核心思想:通过“黑盒复用”降低耦合度
案例对比:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Engine { }
class Car extends Engine { }
class Car { private Engine engine; public Car(Engine engine) { this.engine = engine; } }
|
实际意义:避免继承层次过深导致的“脆弱的基类”问题
7. 迪米特法则 (LoD - Law of Demeter)
定义:一个对象应尽可能少地了解其他对象
核心思想:降低类之间的耦合度
违反案例:
1 2 3 4 5 6 7 8
| class Order { private Customer customer; public Customer getCustomer() { return customer; } }
Order order = getOrder(); String city = order.getCustomer().getAddress().getCity();
|
正确实现:
1 2 3 4 5 6 7 8 9 10
| class Order { private Customer customer; public String getCustomerCity() { return customer.getAddress().getCity(); } }
String city = order.getCustomerCity();
|
实际意义:减少依赖链断裂风险,提高代码健壮性
总结:七大原则的核心理念
原则 |
关键目标 |
一句话记忆 |
SRP |
功能聚焦 |
一个类只做一件事 |
OCP |
易于扩展 |
扩展不修改旧代码 |
LSP |
继承安全 |
子类能顶替父类 |
ISP |
接口精简 |
不用就别强迫我 |
DIP |
解耦依赖 |
依赖抽象不依赖具体 |
CRP |
灵活复用 |
组合优于继承 |
LoD |
减少知晓 |
你的事我不多问 |
实际应用技巧:当发现以下代码症状时,回顾对应原则:
- 频繁修改某个类 → 违反SRP/OCP
- 子类方法抛出
UnsupportedOperationException
→ 违反LSP
- 接口有大量空实现 → 违反ISP
- 单元测试难写 → 违反DIP
- 继承层次超过3层 → 违反CRP
- 调用链超过两个点(如
a.getB().getC()
) → 违反LoD