Почему композиция часто предпочтительнее наследования, и в каких случаях наследование всё же оправдано?
Ответ:
Наследование создаёт сильнейшую связанность в ООП: подкласс зависит от деталей реализации родителя, и это ломается при любом рефакторинге базового класса («хрупкий базовый класс»). Композиция прячет зависимость за интерфейсом — меняется реализация, потребители не замечают.
Наследование создаёт сильнейшую связанность в ООП: подкласс зависит от деталей реализации родителя, и это ломается при любом рефакторинге базового класса («хрупкий базовый класс»). Композиция прячет зависимость за интерфейсом — меняется реализация, потребители не замечают.
Наследование оправдано, когда:
- Есть настоящее отношение «является» (is-a), стабильное во времени: JsonParseError — это ParseError. Всё соответствует LSP — подкласс можно подставить везде, где ожидался родитель, без сюрпризов.
- Работает механизм расширения, заложенный автором: у родителя есть protected-хуки, а наследование — документированный способ кастомизации (как в некоторых фреймворках).
Но честно: в 90% случаев, когда мне хочется наследоваться ради переиспользования кода, я делаю композицию + делегирование или просто утилиту. А в языках с богатой алгебраической типизацией (Kotlin sealed classes, Rust enums) половина классических иерархий вообще заменяется матчингом по вариантам.
вопросы и ответы