Ответ
Наследование не следует использовать в следующих случаях:
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) и когда подкласс действительно представляет специализацию родительского класса.