Какой принцип SOLID обозначается буквой O?

Ответ

Это принцип открытости/закрытости (Open/Closed Principle, OCP). Его суть в том, что классы должны быть открыты для расширения новой функциональности, но закрыты для модификации существующего кода. На практике в C++ это достигается через наследование и полиморфизм, а также с помощью шаблонов (стратегия, посетитель).

Пример из моего опыта: В проекте системы рендеринга у нас был базовый класс Drawable. Когда потребовалось добавить новый тип графического объекта (например, частицы), мы не стали изменять существующий код отрисовки, а создали новый класс ParticleSystem, унаследованный от Drawable.

class Drawable {
public:
    virtual ~Drawable() = default;
    virtual void render(const RenderContext& context) const = 0;
};

class Mesh : public Drawable {
    std::vector<Vertex> vertices;
public:
    void render(const RenderContext& context) const override {
        // Код отрисовки меша
    }
};

// НОВЫЙ ТИП - РАСШИРЕНИЕ БЕЗ ИЗМЕНЕНИЙ
class ParticleSystem : public Drawable {
    std::vector<Particle> particles;
public:
    void render(const RenderContext& context) const override {
        // Код отрисовки системы частиц
    }
};

// Функция отрисовки сцены осталась НЕИЗМЕННОЙ
void renderScene(const std::vector<std::unique_ptr<Drawable>>& objects) {
    for (const auto& obj : objects) {
        obj->render(currentContext);
    }
}

Таким образом, мы расширили функциональность, не затрагивая и не рискуя сломать уже работающий код.

Ответ 18+ 🔞

А, принцип открытости-закрытости! Ну это, блядь, классика, ёпта. Суть-то проще пареной репы, хотя звучит как заклинание из учебника по высшей магии. Объясняю на пальцах, без этих ваших заумных словесных диарей.

Представь себе, у тебя есть класс, который работает, и работает хорошо. Он как отлаженный движок — трогать его страшно, а то накроется медным тазом и всё, будет вам хиросима и нигерсраки. Так вот, ОСР говорит: не лезь ты в его кишки, ёб твою мать! Хочешь добавить новую фичу — не пили его напильником, а расширь его, как резиновую перчатку. Класс должен быть закрыт от изменений, но открыт для расширений. Понимаешь разницу? Не ломать старое, а надстраивать новое поверх.

Вот смотри, реальный случай был. Делали мы систему рендеринга, и был там базовый класс Drawable — всё, что можно нарисовать. Всё работало, пока не пришёл продюсер и не сказал: «А давайте добавим систему частиц, огоньки-снежинки, ёбать колотить!». Ну, подозрение ебать чувствую, что сейчас начнётся: пойдут правки в коде отрисовки, вилкой в глаз или в жопу раз — всё сломается.

Но мы-то не распиздяи! Вместо того чтобы впендюрить логику частиц прямо в старый код, мы просто сделали новый класс ParticleSystem, который унаследовался от того самого Drawable. И всё! Основная функция renderScene, которая гуляет по списку объектов и рисует их, осталась нетронутой, как девичья честь. Она и знать не знает, что там теперь частицы есть, она просто вызывает render() для каждого объекта. А как он там внутри рисуется — его личное дело, да похуй.

class Drawable {
public:
    virtual ~Drawable() = default;
    virtual void render(const RenderContext& context) const = 0; // Вот этот интерфейс — наша основа
};

// Старый проверенный класс. Не трогаем его, он святой.
class Mesh : public Drawable {
    std::vector<Vertex> vertices;
public:
    void render(const RenderContext& context) const override {
        // Код отрисовки меша. Работает, и слава богу.
    }
};

// А вот НОВАЯ ФИЧА! Расширение, а не изменение.
class ParticleSystem : public Drawable {
    std::vector<Particle> particles;
public:
    void render(const RenderContext& context) const override {
        // Код отрисовки системы частиц. Пишем с нуля, никого не трогаем.
        // Можно хоть **ебушки-воробушки** запускать.
    }
};

// И эта функция — сердце системы — вообще в ус не дует.
// Она закрыта для изменений, но открыта для новых типов Drawable. Вот он, принцип!
void renderScene(const std::vector<std::unique_ptr<Drawable>>& objects) {
    for (const auto& obj : objects) {
        obj->render(currentContext); // Вызовется правильный render(), хоть для меша, хоть для частиц.
    }
}

Вот и весь фокус, чувак. Не лезть с сапогами в работающий механизм, а строить новые пристройки. И тогда доверия ебать ноль к стабильности кода превращается в спокойную уверенность. Добавили новый рендерер для UI? Новый класс. Добавили траву? Новый класс. Система только крепчает, а не разваливается от каждого чиха. Красота, я тебе скажу.