Ответ
SOLID — это акроним пяти фундаментальных принципов объектно-ориентированного проектирования и программирования, направленных на создание понятного, гибкого и поддерживаемого кода.
1. Принцип единственной ответственности (Single Responsibility Principle - SRP)
«Один класс — одна причина для изменения». Класс должен решать только одну задачу и нести ответственность только за одну часть функциональности.
// НЕВЕРНО: Класс отвечает и за логику заказа, и за его сохранение, и за логирование.
class OrderProcessor {
void process(Order order) {
// Валидация заказа
// Сохранение в БД
// Отправка email
// Логирование
}
}
// ВЕРНО: Ответственности разделены.
class OrderValidator { /* Только валидация */ }
class OrderRepository { /* Только работа с БД */ }
class EmailService { /* Только отправка писем */ }
class Logger { /* Только логирование */ }
class OrderProcessor {
private OrderValidator validator;
private OrderRepository repository;
// ... внедрение зависимостей
void process(Order order) {
validator.validate(order);
repository.save(order);
// ...
}
}
2. Принцип открытости/закрытости (Open/Closed Principle - OCP)
«Классы должны быть открыты для расширения, но закрыты для модификации». Новую функциональность следует добавлять через создание новых классов (наследование, композиция), а не изменяя существующий код.
// НЕВЕРНО: При добавлении новой фигуры нужно менять метод area().
class AreaCalculator {
public double area(Object shape) {
if (shape instanceof Rectangle) { /* расчёт */ }
else if (shape instanceof Circle) { /* расчёт */ }
// Добавление нового `if` для Triangle
}
}
// ВЕРНО: Используем абстракцию.
interface Shape { double area(); }
class Rectangle implements Shape { /* реализация area() */ }
class Circle implements Shape { /* реализация area() */ }
class Triangle implements Shape { /* НОВЫЙ КЛАСС, не требует изменения AreaCalculator */ }
class AreaCalculator {
public double area(Shape shape) { // Код закрыт для модификации
return shape.area(); // Полиморфный вызов
}
}
3. Принцип подстановки Барбары Лисков (Liskov Substitution Principle - LSP)
«Объекты базового класса должны быть заменяемы объектами производных классов без изменения корректности программы». Подкласс не должен ужесточать предусловия или ослаблять постусловия базового класса.
// НАРУШЕНИЕ LSP: Квадрат не может быть заменой Прямоугольника, если меняется логика установки сторон.
class Rectangle {
protected int width, height;
void setWidth(int w) { width = w; }
void setHeight(int h) { height = h; }
}
class Square extends Rectangle {
@Override
void setWidth(int w) { width = height = w; } // Неожиданное поведение для "прямоугольника"
}
// Клиентский код, ожидающий Rectangle, сломается.
4. Принцип разделения интерфейса (Interface Segregation Principle - ISP)
«Много специализированных интерфейсов лучше одного общего». Клиенты не должны зависеть от методов, которые они не используют.
// ПЛОХО: Принтер вынужден реализовывать ненужный ему метод scan().
interface MultiFunctionDevice {
void print();
void scan();
void fax();
}
class SimplePrinter implements MultiFunctionDevice {
public void print() { /* OK */ }
public void scan() { throw new UnsupportedOperationException(); } // Ненужный метод!
public void fax() { throw new UnsupportedOperationException(); } // Ненужный метод!
}
// ХОРОШО: Интерфейсы разделены.
interface Printer { void print(); }
interface Scanner { void scan(); }
interface Fax { void fax(); }
class SimplePrinter implements Printer { /* реализует ТОЛЬКО print() */ }
class AllInOnePrinter implements Printer, Scanner, Fax { /* реализует всё */ }
5. Принцип инверсии зависимостей (Dependency Inversion Principle - DIP)
«Зависимости должны строиться на абстракциях, а не на деталях».
- Модули верхнего уровня не должны зависеть от модулей нижнего уровня. Оба должны зависеть от абстракций.
- Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.
// НЕВЕРНО: Класс верхнего уровня жёстко зависит от конкретной реализации нижнего уровня. class OrderService { private MySQLOrderRepository repository = new MySQLOrderRepository(); // Прямая зависимость // ... }
// ВЕРНО: Зависимость от абстракции (интерфейса). Конкретная реализация внедряется извне. interface OrderRepository { void save(Order order); } class MySQLOrderRepository implements OrderRepository { / ... / } class MongoOrderRepository implements OrderRepository { / ... / }
class OrderService { // Модуль верхнего уровня private final OrderRepository repository; // Зависимость от абстракции
// Внедрение зависимости через конструктор (Dependency Injection)
public OrderService(OrderRepository repository) {
this.repository = repository;
}
public void processOrder(Order order) {
repository.save(order); // Работает с любым OrderRepository
}
}
**Итог:** Следование SOLID делает код менее связанным, более тестируемым, адаптивным к изменениям и упрощает командную разработку.