Ответ
SOLID — это акроним пяти ключевых принципов объектно-ориентированного проектирования и программирования, направленных на создание понятного, гибкого и поддерживаемого кода. В C++ они применяются особенно важно из-за сложности языка.
1. Принцип единственной ответственности (Single Responsibility Principle - SRP) Класс должен иметь одну и только одну причину для изменения (отвечать за одну задачу).
// Нарушение SRP: класс занимается и логикой, и выводом.
class Report {
std::string data;
public:
void generate() { /* ...логика формирования... */ }
void printToConsole() { std::cout << data; } // Причина для изменения №2
};
// Соблюдение SRP:
class ReportGenerator { void generate() { /* ... */ } };
class ConsoleReporter { void print(const std::string&) { /* ... */ } };
2. Принцип открытости/закрытости (Open/Closed Principle - OCP) Классы должны быть открыты для расширения (новый функционал) и закрыты для модификации (не трогаем существующий код).
// Базовый класс закрыт для модификации.
class Shape {
public:
virtual double area() const = 0; // Виртуальный метод для расширения.
virtual ~Shape() = default;
};
// Новый функционал добавляется новыми классами.
class Circle : public Shape { /* реализация area() */ };
class Square : public Shape { /* реализация area() */ };
// Можно добавить Triangle, не меняя код Shape или существующих функций.
3. Принцип подстановки Барбары Лисков (Liskov Substitution Principle - LSP) Объекты производного класса должны быть заменяемы на объекты базового класса, не нарушая работу программы.
// Нарушение LSP: Квадрат, наследующий Прямоугольник.
class Rectangle {
protected:
int width, height;
public:
virtual void setWidth(int w) { width = w; }
virtual void setHeight(int h) { height = h; }
};
class Square : public Rectangle {
public:
void setWidth(int w) override { width = height = w; } // Меняет и высоту!
// Это сломает код, рассчитывающий на независимость width/height.
};
4. Принцип разделения интерфейса (Interface Segregation Principle - ISP) Много специализированных интерфейсов лучше одного общего. Клиент не должен зависеть от методов, которые он не использует.
// Плохо: Один "толстый" интерфейс.
class IMultiFunctionDevice {
public:
virtual void print() = 0;
virtual void scan() = 0;
virtual void fax() = 0; // Старому принтеру это не нужно!
};
// Хорошо: Разделенные интерфейсы.
class IPrinter { virtual void print() = 0; };
class IScanner { virtual void scan() = 0; };
class IFax { virtual void fax() = 0; };
class SimplePrinter : public IPrinter { /* реализует только print */ };
5. Принцип инверсии зависимостей (Dependency Inversion Principle - DIP) Модули верхнего уровня не должны зависеть от модулей нижнего уровня. Оба должны зависеть от абстракций. Абстракции не должны зависеть от деталей, детали должны зависеть от абстракций.
// Нарушение DIP: Высокоуровневый класс зависит от конкретной БД.
class HighLevelModule {
MySQLDatabase db; // Прямая зависимость от детали.
public:
void saveData() { db.save(); }
};
// Соблюдение DIP:
class IDatabase { // Абстракция
public:
virtual void save(const Data&) = 0;
virtual ~IDatabase() = default;
};
class HighLevelModule {
std::unique_ptr<IDatabase> db; // Зависимость от абстракции.
public:
HighLevelModule(std::unique_ptr<IDatabase> dbPtr) : db(std::move(dbPtr)) {}
void saveData() { db->save(someData); }
};
// Теперь можно передать MySQLDatabase, PostgreSQLDatabase или MockDatabase.
Следование SOLID в C++ облегчает модульное тестирование, рефакторинг и снижает связность компонентов.
Видео-ответы
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶