Принцип подстановки Лисков (LSV) в Python
В этом уроке вы узнаете о принципе подстановки Лисков и о том, как его реализовать в Python.
Что такое принцип подстановки Лисков в Python?
Принцип подстановки Лисков (LSV) — один из пяти принципов SOLID. L в SOLID и означает принцип замены Лисков.
- S – Принцип единой ответственности
- O – Принцип открытости-закрытости
- L – Принцип подстановки Лисков
- I – Принцип разделения интерфейса
- D – Принцип инверсии зависимостей
Принцип подстановки Лисков гласит, что дочерний класс должен быть заменяемым для своего родительского класса. Он направлен на то, чтобы дочерний класс мог занять место своего родительского класса, не вызывая никаких ошибок.
Рассмотрим следующий пример:
from abc import ABC, abstractmethod class Notification(ABC): @abstractmethod def notify(self, message, email): pass class Email(Notification): def notify(self, message, email): print(f'Send {message} to {email}') class SMS(Notification): def notify(self, message, phone): print(f'Send {message} to {phone}') if __name__ == '__main__': notification = SMS() notification.notify('Hello', '[email protected]')
В этом примере у нас есть три класса: Notification, Email и SMS. Классы Email и SMS наследуются от класса Notification.
В абстрактном классе Notification есть метод notify(), который отправляет сообщение на адрес электронной почты. Метод notify() класса Email тоже отправляет сообщение на электронную почту, и это нормально. Однако в классе SMS для отправки сообщения используется номер телефона, а не адрес электронной почты. Поэтому нам нужно изменить сигнатуру метода notify() класса SMS, чтобы он принимал номер телефона вместо адреса электронной почты.
Следующий класс NotificationManager использует объект Notification для отправки сообщения контакту:
class Contact: def __init__(self, name, email, phone): self.name = name self.email = email self.phone = phone class NotificationManager: def __init__(self, notification, contact): self.contact = contact self.notification = notification def send(self, message): if isinstance(self.notification, Email): self.notification.notify(message, contact.email) elif isinstance(self.notification, SMS): self.notification.notify(message, contact.phone) else: raise Exception('The notification is not supported') if __name__ == '__main__': contact = Contact('John Doe', '[email protected]', '(408)-888-9999') notification_manager = NotificationManager(SMS(), contact) notification_manager.send('Hello John')
Метод send() класса NoticationManager принимает объект уведомления. Он проверяет, является ли уведомление экземпляром электронной почты или SMS, и передает адрес электронной почты и телефон контакта методу notify() соответственно.
Соответствие принципу подстановки Лисков
- Сначала переопределите метод notify() класса Notification, чтобы он не включал параметр email:
class Notification(ABC): @abstractmethod def notify(self, message): pass
- Во-вторых, добавьте параметр email в метод __init__ класса Email:
class Email(Notification): def __init__(self, email): self.email = email def notify(self, message): print(f'Send "{message}" to {self.email}')
- В-третьих, добавьте параметр phone в метод __init__ класса SMS:
class SMS(Notification): def __init__(self, phone): self.phone = phone def notify(self, message): print(f'Send "{message}" to {self.phone}')
- В-четвертых, измените класс NotificationManager:
class NotificationManager: def __init__(self, notification): self.notification = notification def send(self, message): self.notification.notify(message)
- Полный код:
from abc import ABC, abstractmethod class Notification(ABC): @abstractmethod def notify(self, message): pass class Email(Notification): def __init__(self, email): self.email = email def notify(self, message): print(f'Send "{message}" to {self.email}') class SMS(Notification): def __init__(self, phone): self.phone = phone def notify(self, message): print(f'Send "{message}" to {self.phone}') class Contact: def __init__(self, name, email, phone): self.name = name self.email = email self.phone = phone class NotificationManager: def __init__(self, notification): self.notification = notification def send(self, message): self.notification.notify(message) if __name__ == '__main__': contact = Contact('John Doe', '[email protected]', '(408)-888-9999') sms_notification = SMS(contact.phone) email_notification = Email(contact.email) notification_manager = NotificationManager(sms_notification) notification_manager.send('Hello John') notification_manager.notification = email_notification notification_manager.send('Hi John')