Skip to content

SOLID 原则

SOLID 是面向对象设计的五个基本原则,是软件工程中经过时间检验的设计指导思想。

五大原则一览

原则全称一句话概括
SSingle Responsibility Principle单一职责:一个类只做一件事
OOpen/Closed Principle开闭原则:对扩展开放,对修改关闭
LLiskov Substitution Principle里氏替换:子类可以替换父类
IInterface Segregation Principle接口隔离:接口要小而专
DDependency Inversion Principle依赖倒置:依赖抽象,不依赖具体

1. 单一职责原则(SRP)

一个类只有一个引起它变化的原因。

java
// ❌ 违反 SRP:同时负责多个职责
class User {
    void saveUser() {}    // 数据存储
    void sendEmail() {}   // 发送邮件
    void generateReport() {}  // 生成报表
}

// ✅ 遵守 SRP:每个类一个职责
class UserRepository {
    void saveUser() {}
}
class EmailService {
    void sendEmail() {}
}
class ReportGenerator {
    void generateReport() {}
}

2. 开闭原则(OCP)

软件实体应该对扩展开放,对修改关闭。

java
// ❌ 违反 OCP:修改现有代码添加新功能
class AreaCalculator {
    double calculate(Object shape) {
        if (shape instanceof Square) {
            // ...
        } else if (shape instanceof Circle) {
            // ...
        }
        // 每加一个形状就要改这里
        return 0;
    }
}

// ✅ 遵守 OCP:扩展新功能
interface Shape {
    double area();
}

class Square implements Shape {
    @Override
    public double area() { return /* ... */; }
}

class Circle implements Shape {
    @Override
    public double area() { return /* ... */; }
}

// 新增形状只需要实现 Shape,不用改这里
class AreaCalculator {
    double calculate(Shape shape) {
        return shape.area();  // 不用改!
    }
}

3. 里氏替换原则(LSP)

子类必须能够替换其基类。

java
// 经典的正方形/矩形问题
class Rectangle {
    protected int width, height;

    public void setWidth(int width) { this.width = width; }
    public void setHeight(int height) { this.height = height; }
    public int area() { return width * height; }
}

class Square extends Rectangle {
    @Override
    public void setWidth(int width) {
        this.width = width;
        this.height = width;  // 违反 LSP!
    }
    @Override
    public void setHeight(int height) {
        this.width = height;
        this.height = height;
    }
}

// 如果一个方法期望 Rectangle,你会得到意外结果
void resize(Rectangle r) {
    r.setWidth(5);
    r.setHeight(4);
    // 期望面积 20,正方形却是 16
}

4. 接口隔离原则(ISP)

客户端不应该依赖它不需要的接口。

java
// ❌ 违反 ISP:大而全的接口
interface Machine {
    void print();
    void scan();
    void fax();
}

// 打印机必须实现 scan 和 fax,即使用不到
class SimplePrinter implements Machine {
    public void print() { }
    public void scan() { throw new UnsupportedOperationException(); }
    public void fax() { throw new UnsupportedOperationException(); }
}

// ✅ 遵守 ISP:小而专的接口
interface Printer { void print(); }
interface Scanner { void scan(); }
interface Fax { void fax(); }

// 每个类只实现需要的接口
class SimplePrinter implements Printer {
    public void print() { }
}
class AllInOnePrinter implements Printer, Scanner, Fax {
    public void print() { }
    public void scan() { }
    public void fax() { }
}

5. 依赖倒置原则(DIP)

高层模块不应该依赖低层模块,两者都应该依赖抽象。

java
// ❌ 违反 DIP:高层依赖低层
class OrderService {
    private MySQLRepository repository;  // 直接依赖具体实现

    public void save(Order order) {
        repository.save(order);
    }
}

// ✅ 遵守 DIP:依赖抽象
interface Repository {
    void save(Order order);
}

class OrderService {
    private final Repository repository;  // 依赖抽象

    public OrderService(Repository repository) {
        this.repository = repository;
    }

    public void save(Order order) {
        repository.save(order);
    }
}

class MySQLRepository implements Repository {
    public void save(Order order) { /* ... */ }
}

class MongoDBRepository implements Repository {
    public void save(Order order) { /* ... */ }
}

实际应用:重构示例

重构前

java
// 一个类做了太多事情
class UserManager {
    private DatabaseConnection db;

    void createUser(User user) {
        // 验证
        if (user.getEmail() == null) throw new Exception("Email required");
        // 保存到数据库
        db.execute("INSERT ...");
        // 发送欢迎邮件
        emailService.send(user.getEmail(), "Welcome");
        // 记录日志
        logger.info("User created: " + user.getEmail());
    }
}

重构后

java
// 单一职责,每个类只做一件事
class UserValidator {
    void validate(User user) {
        if (user.getEmail() == null) {
            throw new ValidationException("Email required");
        }
    }
}

interface UserRepository {
    void save(User user);
}

interface NotificationService {
    void notifyUserCreated(User user);
}

interface AuditLogger {
    void logUserCreation(User user);
}

class UserService {
    private final UserValidator validator;
    private final UserRepository repository;
    private final NotificationService notifier;
    private final AuditLogger logger;

    public UserService(UserValidator validator,
                       UserRepository repository,
                       NotificationService notifier,
                       AuditLogger logger) {
        this.validator = validator;
        this.repository = repository;
        this.notifier = notifier;
        this.logger = logger;
    }

    public void createUser(User user) {
        validator.validate(user);      // 验证
        repository.save(user);         // 保存
        notifier.notifyUserCreated(user);  // 通知
        logger.logUserCreation(user);  // 日志
    }
}

SOLID 之间的关系

依赖倒置原则(DIP)

开闭原则(OCP)

里氏替换原则(LSP)

单一职责原则(SRP)

接口隔离原则(ISP)

SOLID 原则不是孤立的,它们相互关联、相互支撑。理解这些原则背后的思想,比死记硬背更重要。

总结

原则核心思想反面典型
S职责单一上帝类
O扩展开放,修改关闭无限修改
L子类替换父类菱形继承
I接口小而专大而全接口
D依赖抽象依赖具体

记住:好的设计是能够经受变化考验的设计。SOLID 原则帮助我们构建这样的系统。

基于 VitePress 构建