SOLID 五原则用于指导面向对象设计,目标是让系统:
更易扩展(Extensible)
更易维护(Maintainable)
更易测试(Testable)
更松耦合(Loosely Coupled)
更清晰(Clean & Understandable)
SOLID 包含五条原则:
S — 单一职责原则(Single Responsibility Principle)
O — 开闭原则(Open Closed Principle)
L — 里氏替换原则(Liskov Substitution Principle)
I — 接口隔离原则(Interface Segregation Principle)
D — 依赖倒置原则(Dependency Inversion Principle)
1 单一职责原则(SRP)
一个类应该只有一个理由引起它发生变化。
一个模块应该只负责一个功能。
1.1 为什么要单一职责?
若一个类承担多种职责,则:
修改 A 可能会影响 B
代码难懂、难测试
改动风险大
职责边界混乱
单一职责能实现:
单一变化点
更小的类
高内聚
易扩展易维护
1.2 常见反例
public class UserService {
public void register(String username) {
// 注册处理
}
public void sendEmail(String username) {
// 发送邮件
}
}
UserService 同时负责:
注册业务
邮件通知
违反 SRP。
1.3 正确做法(拆分职责)
public class UserService {
public void register(String username) {
// 注册
}
}
public class EmailService {
public void sendEmail(String username) {
// 发邮件
}
}
每个类只负责一件事。
1.4 SRP 在系统中的体现
常见 SRP 体现方式:
分层架构:Controller、Service、Repository
工具类不混业务逻辑
业务规则与持久化分离
Web 层与逻辑层独立
SRP 是重构最常用原则。
2 开闭原则(OCP)
软件实体应该对扩展开放,对修改关闭。
意思:
新需求应该通过扩展新代码实现
而不是通过修改旧代码实现
这样可以降低破坏风险。
2.1 错误示例
折扣策略随用户等级变化。
public class DiscountService {
public double discount(String level) {
if (level.equals("VIP")) return 0.8;
if (level.equals("SuperVIP")) return 0.6;
return 1.0;
}
}
增加 GoldVIP 时需要修改源代码,违反 OCP。
2.2 正确示例(使用抽象扩展)
public interface Discount {
double getRate();
}
public class VipDiscount implements Discount {
public double getRate() { return 0.8; }
}
public class SuperVipDiscount implements Discount {
public double getRate() { return 0.6; }
}
新增 GoldVipDiscount,不需修改原逻辑,只需增加类。
2.3 OCP 与设计模式关系
OCP 是策略模式、工厂模式、模板方法、装饰器等设计模式的核心思想。
设计模式几乎都是为了满足 OCP。
3 里氏替换原则(LSP)
子类对象必须能够替换父类对象,并保证程序行为不变。
换句话说:
子类应遵守父类的约定
不能破坏父类的功能
不能改变父类接口的顺序/含义/异常行为
3.1 错误示例
class Rectangle {
void setWidth(int w);
void setHeight(int h);
}
class Square extends Rectangle {
void setWidth(int w) { super.setWidth(w); super.setHeight(w); }
void setHeight(int h) { super.setWidth(h); super.setHeight(h); }
}
Square 强制宽=高,破坏了 Rectangle 应有的行为。
因此它们不应使用继承关系。
3.2 正确做法
使用接口 Shape:
interface Shape {
int area();
}
Rectangle 与 Square 都实现 Shape,而不是互相继承。
3.3 LSP 的本质
“行为兼容性”比“结构兼容性”更重要。
继承不是为了复用代码,而是为了建立“is-a”关系(行为一致)。
4 接口隔离原则(ISP)
客户端不应该被迫依赖它不使用的方法。
接口应当细分为更小、更具体的接口。
4.1 常见反例:大接口
public interface Animal {
void run();
void fly();
void swim();
}
Dog 实现 Animal:
class Dog implements Animal {
public void run() {}
public void fly() {} // 不需要却被迫实现
public void swim() {}
}
违反 ISP。
4.2 正确做法(拆接口)
interface Runnable { void run(); }
interface Flyable { void fly(); }
interface Swimmable { void swim(); }
Dog 只实现它需要的:
class Dog implements Runnable, Swimmable {
...
}
4.3 ISP 的实际价值
降低接口耦合
增强灵活性
避免“胖接口”问题
提高模块可替换性
5 依赖倒置原则(DIP)
高层模块不应该依赖低层模块,两者应该依赖于抽象。
抽象不应该依赖具体实现,具体实现应该依赖于抽象。
5.1 错误示例(强耦合)
class UserService {
MySQLRepository repo = new MySQLRepository();
}
UserService 强依赖 MySQL,如果数据库换成 MongoDB,需要改业务代码。
违反 DIP。
5.2 正确做法(依赖接口)
抽象接口:
interface UserRepository {
void save();
}
具体实现:
class MySQLRepository implements UserRepository { ... }
class MongoRepository implements UserRepository { ... }
高层依赖接口:
class UserService {
private UserRepository repo;
public UserService(UserRepository repo) {
this.repo = repo;
}
}
这就是 Spring IOC 的思想——依赖倒置。
5.3 DIP 的价值
易测试(可替换 mock)
易扩展(替换实现)
降低耦合(高层不依赖低层细节)
6 SOLID 总结
SOLID 是构建高质量软件的核心思想。
7 额外:SOLID 与设计模式的关系
工厂模式 → DIP + OCP
策略模式 → OCP
装饰器模式 → OCP
模板方法 → OCP
组合模式 → LSP
接口分离 → ISP
Spring IOC → DIP