SOLID principle
SOLID 是面向对象设计的五大基本原则,由 Robert C. Martin(Bob 大叔)提出,用于指导开发者编写可维护、可扩展、可测试的高质量代码。SOLID 是五个原则的首字母缩写,分别对应:
1. S – 单一职责原则(Single Responsibility Principle, SRP)
一个类应该只有一个引起它变化的原因。
- 解释:每个类只负责一项职责,避免“万能类”。
- 好处:降低耦合,提高可读性和可维护性。
例子:
// 错误:UserService 既负责用户注册,又负责发送邮件
class UserService {
void registerUser(User user) {
// 注册逻辑
EmailSender.send(user.email, "欢迎注册");
}
}
// 正确:职责分离
class UserService {
void registerUser(User user) {
// 注册逻辑
}
}
class EmailService {
void sendWelcomeEmail(User user) {
EmailSender.send(user.email, "欢迎注册");
}
}
2. O – 开闭原则(Open/Closed Principle, OCP)
软件实体应对扩展开放,对修改关闭。
- 解释:通过扩展(如继承、接口实现)来增加功能,而不是修改已有代码。
- 好处:避免引入 bug,增强系统稳定性。
例子:
// 错误:每次新增形状都要修改 drawAllShapes 方法
void drawAllShapes(List<Shape> shapes) {
for (Shape s : shapes) {
if (s.type == "circle") drawCircle(s);
else if (s.type == "square") drawSquare(s);
}
}
// 正确:使用多态扩展
interface Shape {
void draw();
}
class Circle implements Shape {
void draw() { /* 画圆 */ }
}
class Square implements Shape {
void draw() { /* 画方形 */ }
}
3. L – 里氏替换原则(Liskov Substitution Principle, LSP)
子类对象应该能够替换父类对象,而不影响程序的正确性。
- 解释:子类必须完全实现父类的行为,不能“背叛”父类的契约。
- 好处:保证继承体系的正确性。
反例:
class Bird {
void fly() {}
}
class Penguin extends Bird {
void fly() { throw new Exception("企鹅不会飞"); } // 违反 LSP
}
4. I – 接口隔离原则(Interface Segregation Principle, ISP)
客户端不应该被迫依赖它们不使用的方法。
- 解释:接口要小而专一,避免“胖接口”。
- 好处:减少耦合,提高灵活性。
例子:
// 错误:胖接口
interface Worker {
void work();
void eat();
}
// 正确:拆分接口
interface Workable {
void work();
}
interface Eatable {
void eat();
}
class Robot implements Workable {
void work() {}
}
class Human implements Workable, Eatable {
void work() {}
void eat() {}
}
5. D – 依赖倒置原则(Dependency Inversion Principle, DIP)
高层模块不应该依赖低层模块,二者都应该依赖于抽象。
- 解释:面向接口编程,而不是面向实现编程。
- 好处:降低耦合,增强可测试性和可扩展性。
例子:
// 错误:高层类直接依赖具体实现
class LightBulb {
void turnOn() {}
}
class Switch {
LightBulb bulb = new LightBulb();
void operate() { bulb.turnOn(); }
}
// 正确:依赖抽象
interface Switchable {
void turnOn();
}
class LightBulb implements Switchable {
void turnOn() {}
}
class Switch {
Switchable device;
Switch(Switchable device) { this.device = device; }
void operate() { device.turnOn(); }
}
✅ 总结一句话记忆:
| 原则 | 一句话记忆 |
|---|---|
| SRP | 一个类只做一件事 |
| OCP | 加功能不改老代码 |
| LSP | 子类别“背叛”父类 |
| ISP | 接口要小而精 |
| DIP | 依赖接口,不依赖实现 |