В каких случаях не следует использовать наследование в ООП?

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

Ответ

Наследование не следует использовать в следующих случаях:

1. При нарушении принципа подстановки Лисков (LSP): Когда подкласс не может заменить родительский класс без изменения корректности программы.

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

class Rectangle {
    protected int width, height;

    public void setWidth(int w) { width = w; }
    public void setHeight(int h) { height = h; }
}

class Square extends Rectangle {
    @Override
    public void setWidth(int w) {
        super.setWidth(w);
        super.setHeight(w); // Нарушает ожидаемое поведение Rectangle
    }
}

2. Для простого повторного использования кода без логической связи "является":

// Плохо: Car не является Engine
class Car extends Engine {
    // Наследование для получения методов Engine
}

// Лучше: композиция
class Car {
    private Engine engine;
    public Car(Engine engine) {
        this.engine = engine;
    }
}

3. Когда нужно лишь добавить функциональность:

  • Предпочитайте интерфейсы
  • Используйте паттерн Декоратор
  • Применяйте делегирование

4. Для моделирования изменяющихся требований:

  • Наследование создаёт жёсткую связь
  • Изменение родительского класса влияет на всех потомков
  • Альтернатива: Стратегия, Состояние, Композиция

Правило: Используйте наследование только при наличии отношения "является" (is-a) и когда подкласс действительно представляет специализацию родительского класса.