Что такое принципы 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 своими словами.