В этом уроке мы разберем, как некоторые подходы могут подорвать идею полиморфизма в наших программах. Мы разберем следующие популярные способы нарушения полиморфизма: формирование объектов, проверка типов и слишком много условий.
Формирование объектов
Изучим функцию ниже. Можно ли считать ее полиморфной?
class EmailSender:
def send(self, email, message):
return f"Sending '{message}' to {email}"
class User:
def __init__(self, email):
self.email = email
def get_email(self):
return self.email
def say_hi_by_email(user):
sender = EmailSender()
return sender.send(user.get_email(), "Hi!")
С одной стороны объект user
передается в функцию извне. Это дает возможность подменить его, передав туда объект другого класса. Но внутри функции явно используется класс EmailSender
, и подменить его невозможно без переписывания самого кода.
Такой код демонстрирует важную идею: полиморфизм возможен, когда объект передается в функцию извне, а не создается внутри нее.
Проверка типов
Рассмотрим еще один пример. Есть ли полиморфизм в следующем коде?
class User:
def __init__(self, name):
self.name = name
class Guest:
pass
def say_hi(user):
if isinstance(user, User):
return f"Hello, {user.name}!"
elif isinstance(user, Guest):
return "Hello, guest!"
else:
return "Who are you?"
В этом примере объект передается извне, что может говорить о полиморфизме. Но внутри функции явно проверяется тип объекта. Это означает, что поведение определяется не объектом, а функцией.
Функция жестко связана с определенными типами, и при изменении этих типов ее придется переписать. Это не совсем полиморфизм, как мы его понимаем.
В подобной ситуации есть два подхода к решению:
- Перенести всю логику внутрь классов. Тогда код функции
say_hi
будет выглядеть так:return user.say_hi()
. Но следует быть осторожным. С этим подходом легко получить «божественный объект», который управляет всем - Второй способ — введение нового интерфейса в виде методов
is_user
иis_guest
:
def say_hi(user):
if user.is_user():
return f"Hello, {user.name}!"
elif user.is_guest():
return "Hello, guest!"
else:
return "Who are you?"
Хотя количество кода не уменьшилось, этот подход лучше поддерживает полиморфизм. Код теперь опирается на методы, а не на типы. И изменение структуры классов не затронет эту функцию, если сама логика останется прежней.
Выводы
Полиморфизм — это мощный инструмент, который делает наш код более гибким и расширяемым. Но его легко нарушить, применяя неправильные подходы. Избегая этих подходов, мы можем написать более чистый и модульный код, который легче понять и поддерживать.
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.