Зарегистрируйтесь, чтобы продолжить обучение

Композиция вместо наследования Python: Погружаясь в классы

В объектно-ориентированном программировании наследование является одним из наиболее сложных механизмов. Чем больше мы изучаем его, тем больше становится очевидным, что использование наследования требует особого внимания и понимания. Еще наследование имеет некоторые фундаментальные ограничения, которые могут привести к проблемам при его использовании.

В этом уроке подробнее разберемся с наследованием и рассмотрим его возможные ограничения и альтернативы.

Ограничения применения наследования

Ключевая проблема с иерархиями в том, что наш мир не иерархичен. Любая классификация всегда опирается на конкретный признак, который интересует нас в конкретный момент времени. И эта же классификация становится бесполезной, если берется другой признак.

Это хорошо видно в интернет-магазинах, у которых навороченные фильтры для выбора товара: группировка по производителю, по применимости, по безопасности для детей и так далее. В каждой конкретной ситуации будет своя структура.

Возьмем понятие User. Статьи по наследованию часто любят показывать иерархии пользователей, создавая у разработчиков уверенность, что мир так и устроен.

Попробуем представить, по каким признакам можно построить иерархию пользователей:

  • По полу (MaleUser, FemaleUser)
  • На основе аутентификации (User, Guest)
  • По роли (Admin, Member)
  • По типу должности (Marketer, SalesManager, Programmer, Tester, Player)
  • По принадлежности к какой-либо группе (UserFromRussia, UserWhoLikesSpartak)
  • По источнику (UserFromFacebook, UserFromGithub)
  • По типу хранилища (SQLUser, LocalStorageUser)

Всё это может и будет встречаться в рамках даже одной программы. В зависимости от того, какую задачу мы решаем, может понадобиться разное представление.

Наследование ограничивает свободу действий. Оно приковывает нас к определенной структуре, которую невозможно изменить. Единственным решением в данном контексте является использование большего числа наследований. В итоге у нас будет комбинация всех возможных поведений, которые встретятся в программе, а это иерархии с десятками и сотнями классов. При этом это должно согласовываться с интерфейсами, которые тоже могут расширять друг друга.

Можно использовать множественное наследование, но в некоторых языках оно делает все еще сложнее. Поэтому от него отказались.

В итоге у разработчиков сформировалась общая позиция по отношению к наследованию: композиция вместо наследования. Если попробовать загуглить эту фразу, то поисковик покажет невероятное количество статей по этой теме.

Этот подход мы уже изучали в курсе «Python: Полиморфизм». Он сводится к более грамотному разделению зон ответственности в приложении и делегированию функциональности другим объектам, нужным в конкретных ситуациях.

С этого момента начинаются сложности. В большинстве статей, посвященных этому вопросу, приводятся либо ошибочные, либо слишком искусственные примеры, которые не дают особого понимания.

Для начала отделим две разные причины использования наследования. Одна из них связана с прямым назначением наследования, другая вытекает из неверного понимания принципов организации кода.

Использование не по назначению

Яркий пример использования наследования не по назначению — смешивание разных уровней абстракции. Выше был пример про пользователей, разделяемых по типу хранилища — SQLUser.

Можно задаться вопросом, как пользователь с точки зрения нашей предметной области связан с техническими аспектами хранения этих пользователей? Никак не связан, такой код в принципе не должен существовать, и наследование для него не предназначено.

Такой код появляется не от незнания ООП, а от непонимания общих принципов организации кода, построения абстракций. Эта тема не является специфичной для ООП, но ООП делает ее сложнее из-за большого числа новых сущностей, которое оно вводит.

Обязательно прочитайте эту статью, которая проливает свет на архитектуру.

Парадокс состоит в том, что фраза composition over inheritance (композиция вместо наследования) относится к такому использованию наследования. То есть проблема не в наследовании. Проблема в том, что оно оказалось удобным способом организации кода для тех, кто не очень хорошо знает, как его организовывать, что такое барьеры абстракции и слои приложения.

Использование по назначению

Необходимость наследования классов возникает там, где классы связаны общим кодом. И это не отношение подтипов. В такой ситуации нужна альтернатива наследованию. И здесь появляются варианты.

В самом простом случае общий код — не публичный. Тогда хватит обычной функции, которую эти классы будут использовать внутри себя. А если общий код был публичным? Большинство руководств рекомендуют создать соответствующий интерфейс и реализовать его в каждом из классов. Основной недостаток такого подхода — дублирование кода в каждом классе. То есть мы пришли к тому, от чего пытались уйти.

Решение этой проблемы известно довольно давно и называется миксинами. Это альтернатива правильному использованию наследования. С ними пропадает любая необходимость использовать наследование, включая абстрактные классы.

Выводы

Наследование является сложным и многогранным механизмом, и его использование требует тщательного понимания и внимания к деталям. Неправильное использование может привести к проблемам в коде и снижению его поддерживаемости. Однако, если знать альтернативы, такие как миксины и правильное использование композиции, разработчики могут избежать этих проблем и создать более гибкие и модульные системы.


Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы
профессия
Программирование на Python, Разработка веб-приложений и сервисов используя Django, проектирование и реализация REST API
10 месяцев
с нуля
Старт 26 декабря

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»