Вопрос проверяет понимание принципов объектно-ориентированного проектирования и умение выбирать композицию вместо наследования для избежания хрупкой архитектуры.
Наследование — мощный механизм ООП, но его неправильное применение приводит к хрупкому и трудно поддерживаемому коду. Основная проблема возникает, когда разработчики используют наследование для переиспользования кода, а не для моделирования естественной иерархии "является" (is-a).
class Bird {
fly() { /* летает */ }
}
class Penguin extends Bird {
fly() { throw new Error('Пингвины не летают'); }
}Здесь нарушен LSP: пингвин не является летающей птицей в контексте метода fly(). Лучше выделить интерфейс Flyable и использовать композицию.
Композиция (has-a) предпочтительнее, когда нужно собрать объект из независимых поведений. Например, вместо создания иерархии классов для разных типов сотрудников, можно создать класс Employee с полями role, salaryCalculator и т.д.
Используйте наследование только для строгих иерархий "является" с соблюдением LSP. Во всех остальных случаях, особенно при переиспользовании кода, отдавайте предпочтение композиции — это делает систему гибкой и устойчивой к изменениям.