Gymterview
middle

Что такое принципы SOLID?

SOLID – пять принципов объектно-ориентированного проектирования, сформулированных Робертом Мартином. Они помогают создавать код, который легко поддерживать, расширять и тестировать.

S – Single Responsibility Principle (Принцип единственной ответственности)

Класс должен иметь только одну причину для изменения.

Пример кода
// НАРУШЕНИЕ -- класс и обрабатывает заказ, и отправляет email, и сохраняет в БД
class OrderService {
    void processOrder(Order order) {
        validate(order);
        save(order);                    // ответственность: persistence
        sendEmail(order.getEmail());    // ответственность: уведомления
        generatePdf(order);             // ответственность: отчёты
    }
}

// ПРАВИЛЬНО -- каждый класс отвечает за одно
class OrderService {
    private final OrderRepository repository;
    private final NotificationService notifications;

    void processOrder(Order order) {
        validate(order);
        repository.save(order);
        notifications.orderCreated(order);
    }
}

O – Open/Closed Principle (Принцип открытости/закрытости)

Класс открыт для расширения, закрыт для модификации.

Пример кода
// НАРУШЕНИЕ -- добавление нового типа скидки требует изменения метода
double calculateDiscount(Order order) {
    if (order.getType() == REGULAR) return 0;
    if (order.getType() == VIP) return order.getTotal() * 0.1;
    if (order.getType() == PREMIUM) return order.getTotal() * 0.2; // добавили -- модифицировали
}

// ПРАВИЛЬНО -- расширение через новый класс, без модификации существующего
interface DiscountStrategy {
    double calculate(Order order);
}
class VipDiscount implements DiscountStrategy { ... }
class PremiumDiscount implements DiscountStrategy { ... }
// Добавление нового типа = новый класс, существующий код не трогается

L – Liskov Substitution Principle (Принцип подстановки Барбары Лисков)

Объекты подклассов должны быть заменяемы объектами суперкласса без нарушения корректности программы.

Пример кода
// НАРУШЕНИЕ -- Square нарушает контракт Rectangle
class Rectangle {
    void setWidth(int w) { this.width = w; }
    void setHeight(int h) { this.height = h; }
}
class Square extends Rectangle {
    @Override void setWidth(int w) { this.width = w; this.height = w; } // сюрприз!
}

// ПРАВИЛЬНО -- отдельные типы или общий интерфейс Shape
interface Shape {
    double area();
}
record Rectangle(double width, double height) implements Shape {
    public double area() { return width * height; }
}
record Square(double side) implements Shape {
    public double area() { return side * side; }
}

I – Interface Segregation Principle (Принцип разделения интерфейса)

Клиент не должен зависеть от методов, которые он не использует.

Пример кода
// НАРУШЕНИЕ -- один "жирный" интерфейс
interface Worker {
    void work();
    void eat();     // роботу не нужно
    void sleep();   // роботу не нужно
}

// ПРАВИЛЬНО -- разделённые интерфейсы
interface Workable { void work(); }
interface Feedable { void eat(); }
class Human implements Workable, Feedable { ... }
class Robot implements Workable { ... } // только нужные методы

D – Dependency Inversion Principle (Принцип инверсии зависимостей)

Модули верхнего уровня не должны зависеть от модулей нижнего уровня. Оба должны зависеть от абстракций.

Пример кода
// НАРУШЕНИЕ -- сервис зависит от конкретной реализации
class OrderService {
    private MySqlOrderRepository repo = new MySqlOrderRepository(); // жёсткая связь
}

// ПРАВИЛЬНО -- зависимость от абстракции
class OrderService {
    private final OrderRepository repo; // интерфейс
    OrderService(OrderRepository repo) { this.repo = repo; } // внедрение
}

Важное

  • SOLID – ориентиры, не догмы; слепое следование может привести к over-engineering
  • SRP – самый важный и часто нарушаемый принцип
  • DIP – фундамент для Dependency Injection (Spring IoC)
  • LSP – ключ к корректному наследованию; нарушение – частый источник багов

Частые ошибки

  • Один класс = один метод – это не SRP; SRP = одна причина для изменения
  • Абстракция ради абстракции – интерфейс с одной реализацией не нужен, если не планируется подмена
  • Наследование вместо композиции – LSP нарушается чаще при глубокой иерархии

Как используется в 2026

  • SOLID – стандартный вопрос на собеседовании Middle+
  • Spring Framework построен на DIP (IoC-контейнер)
  • OCP реализуется через Strategy, Plugin-архитектуру, Spring Profiles

На собеседовании: от Middle ожидают не заученные определения, а примеры из собственного опыта: “я нарушал SRP, когда…”, “мы применили OCP через…”. Частая ошибка – путать SRP с “один метод в классе” и не уметь объяснить DIP своими словами.