Принцип подстановки Лисков (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')
Похожие посты
Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *