Какой принцип SOLID нарушается при добавлении нового метода в унаследованный класс?

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

Ответ

Такое изменение может нарушить Принцип подстановки Барбары Лисков (Liskov Substitution Principle, LSP).

Суть LSP: Объекты подкласса должны быть заменяемы на объекты родительского класса без изменения корректности программы. Поведение подкласса должно соответствовать контракту (ожиданиям) базового класса.

Нарушение при добавлении метода:

  1. Сужение предусловий: Новый метод в подклассе может накладывать более строгие условия для работы, чем ожидается от родителя.
  2. Расширение постусловий: Метод может гарантировать меньше, чем метод родителя.
  3. Нарушение инвариантов: Метод может изменять состояние объекта способом, недопустимым для родительского класса.

Классический пример нарушения 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 {
    // Нарушение LSP: изменяет контракт методов setWidth/setHeight.
    @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; // Успех для Rectangle, провал для Square (получится 16).
}

Вывод: Добавление метода, которое меняет семантику или инварианты унаследованного поведения, нарушает LSP. Часто это сигнал к пересмотру иерархии наследования в пользу композиции.