Объясни принцип открытости/закрытости (Open-Closed Principle) из SOLID и приведи пример на Java.

«Объясни принцип открытости/закрытости (Open-Closed Principle) из SOLID и приведи пример на Java.» — вопрос из категории ООП, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Принцип открытости/закрытости (Open/Closed Principle, OCP): Программные сущности (классы, модули, функции) должны быть открыты для расширения, но закрыты для модификации.

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

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

class AreaCalculator {
    public double calculateArea(Object shape) {
        if (shape instanceof Circle) {
            Circle c = (Circle) shape;
            return Math.PI * c.radius * c.radius;
        } else if (shape instanceof Rectangle) {
            Rectangle r = (Rectangle) shape;
            return r.width * r.height;
        }
        // Добавление новой фигуры (Triangle) требует изменения этого метода!
        throw new IllegalArgumentException("Unknown shape");
    }
}

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

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

// 2. Конкретные реализации. Их код закрыт для модификации.
class Circle implements Shape {
    private double radius;
    public Circle(double radius) { this.radius = radius; }
    @Override
    public double area() { return Math.PI * radius * radius; }
}

class Rectangle implements Shape {
    private double width, height;
    public Rectangle(double w, double h) { width = w; height = h; }
    @Override
    public double area() { return width * height; }
}

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

Как добавить новую фигуру Triangle?

  1. Создаём новый класс Triangle implements Shape с реализацией area().
  2. Никаких изменений в классах Circle, Rectangle или AreaCalculator не требуется.

Выгода: Система становится устойчивой к изменениям, снижается риск внесения ошибок в существующий код.