Какой принцип SOLID напрямую связан с корректным использованием наследования?

«Какой принцип SOLID напрямую связан с корректным использованием наследования?» — вопрос из категории ООП, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

С корректным использованием наследования напрямую связан принцип Liskov Substitution Principle (LSP) — "Принцип подстановки Барбары Лисков".

Формулировка: Объекты базового класса должны быть заменяемыми объектами его подклассов без изменения корректности программы. Наследующий класс должен дополнять, а не изменять поведение родителя.

Суть принципа: LSP устанавливает строгие правила для наследования. Если класс S является подтипом класса T, то везде, где используется T, можно безопасно использовать S, не ломая логику.

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

class Rectangle {
    protected int width, height;
    public void setWidth(int w) { width = w; }
    public void setHeight(int h) { height = h; }
    public int getArea() { return width * height; }
}

// Квадрат «является» прямоугольником с математической точки зрения,
// но с точки зрения поведения — нет.
class Square extends Rectangle {
    @Override
    public void setWidth(int w) {
        super.setWidth(w);
        super.setHeight(w); // Нарушение: изменение высоты при установке ширины
    }
    @Override
    public void setHeight(int h) {
        super.setHeight(h);
        super.setWidth(h); // Нарушение: изменение ширины при установке высоты
    }
}

// Код, который работает с Rectangle, сломается для Square
void testArea(Rectangle r) {
    r.setWidth(5);
    r.setHeight(4);
    assert r.getArea() == 20; // Утверждение провалится для Square (area=16)
}

Вывод: LSP требует, чтобы подклассы были семантически совместимы со своими суперклассами, а не только синтаксически. Наследование должно означать "является" в строгом поведенческом смысле.