Что означает принцип открытости/закрытости (O) в SOLID?

Ответ

O в SOLID означает Open/Closed Principle (OCP) — Принцип открытости/закрытости.

Формулировка: Программные сущности (классы, модули, функции) должны быть открыты для расширения, но закрыты для модификации.

  • Закрыты для модификации: Исходный код стабильной, протестированной сущности не должен изменяться для добавления новой функциональности.
  • Открыты для расширения: Новую функциональность следует добавлять путем создания новых сущностей (через наследование, композицию, реализацию интерфейсов).

Пример нарушения OCP:

class AreaCalculator {
    public double calculateArea(Object shape) {
        if (shape instanceof Rectangle) {
            // ... расчет для прямоугольника
        } else if (shape instanceof Circle) {
            // ... расчет для круга
        }
        // При добавлении новой фигуры нужно МОДИФИЦИРОВАТЬ этот метод!
        throw new IllegalArgumentException("Unknown shape");
    }
}

Пример соблюдения OCP:

// Абстракция, открытая для расширения
interface Shape {
    double area();
}

// Конкретные реализации. Добавление новой фигуры не требует изменения существующего кода.
class Rectangle implements Shape {
    private double width, height;
    @Override
    public double area() { return width * height; }
}

class Circle implements Shape {
    private double radius;
    @Override
    public double area() { return Math.PI * radius * radius; }
}

// Класс закрыт для модификации. Он работает с абстракцией Shape.
class AreaCalculator {
    public double calculateTotalArea(List<Shape> shapes) {
        return shapes.stream()
                     .mapToDouble(Shape::area)
                     .sum();
    }
}

Почему это важно: OCP уменьшает риск появления ошибок в уже работающем коде, облегчает поддержку и делает систему более устойчивой к изменениям.

Ответ 18+ 🔞

А, ну это про тот самый принцип, когда всё должно быть как хороший шкаф — закрыто нахуй, но с дверцами, чтобы новое барахло можно было пихать без переклейки обоев.

Слушай, вот есть у тебя класс, который площадь считает. И пишешь ты его по-простому, как все начинают:

class AreaCalculator {
    public double calculateArea(Object shape) {
        if (shape instanceof Rectangle) {
            // ... расчет для прямоугольника
        } else if (shape instanceof Circle) {
            // ... расчет для круга
        }
        // А тут, блядь, что делать, если треугольник приползёт?
        throw new IllegalArgumentException("Unknown shape");
    }
}

И живёшь ты так, пока начальник не приходит с криком: «Срочно добавляй пятиугольники, ёпта!». И ты, сука, лезешь в этот уже работающий, отлаженный метод, начинаешь там else if (shape instanceof Pentagon) лепить, и по чистой случайности задеваешь строчку с кругом. И всё, пиздец — в продакшене у клиентов вместо площади круга начинает выводиться «Ядрёна вошь!». И тебя потом ищут с вилами.

А принцип OCP тебе говорит: «Э, сабака, сука, э, бошка думай!». Не надо лазить в старый код! Сделай так, чтобы новую хуйню можно было прикручивать, не откручивая старую.

Вот как умные дяди делают:

// Объявляем общую идею, контракт. Это как дырка в шкафу, куда что угодно можно пихнуть.
interface Shape {
    double area();
}

// Каждая фигура сама знает, как свою площадь посчитать. Прямоугольник — умный, круг — не дурак.
class Rectangle implements Shape {
    private double width, height;
    @Override
    public double area() { return width * height; }
}

class Circle implements Shape {
    private double radius;
    @Override
    public double area() { return Math.PI * radius * radius; }
}

И тогда твой главный калькулятор становится тупым, как пробка, и от этого невероятно стабильным:

class AreaCalculator {
    public double calculateTotalArea(List<Shape> shapes) {
        return shapes.stream()
                     .mapToDouble(Shape::area)
                     .sum();
    }
}

Суть в чём, блядь? Тебе завтра скажут добавить звёздочку-десятиугольник или, там, спираль Архимеда. Ты просто создашь новый класс Star implements Shape, напишешь в нём свою формулу площади, и впихнёшь его в общий список. А в AreaCalculator ты даже заглядывать не будешь! Он, блядь, закрыт для модификации, как банковский сейф. Но при этом система открыта для расширения — хоть двадцать новых фигур напили.

Получается эдакий волшебный конструктор: старые кирпичи не трогаешь, чтобы не развалить стену, а новые пристраиваешь сбоку. И терпения ебать ноль тратить не надо, чтобы всё перепроверять. Красота, ёпта!