SOLID Principle (L- Liskov Substitution Principle)
The Liskov Substitution Principle (LSP) is a fundamental principle in object-oriented programming that ensures that derived classes can substitute their base classes without causing any issues or breaking the code. By adhering to this principle, inheritance is used correctly, and new functionality added to a subclass does not break existing code that uses the base class. This ensures the correctness, reliability, and scalability of the software, making it more reusable and extensible.
Let's consider an example(in python) of a Notification service that sends messages through email and SMS. The Notification class is an abstract class that declares an abstract method, send(), which is implemented in the derived classes, Email and SMS.
from abc import ABC, abstractmethod
class Notification(ABC):
"""Notification Base Class"""
@abstractmethod
def send(self, message: str, email: str) -> None:
pass
class Email(Notification):
"""Send Email to an Email Address"""
def send(self, message: str, email: str) -> None:
print(f'Send {message} to {email}')
class SMS(Notification):
"""Send SMS to a Phone Number"""
def send(self, message: str, phone: str) -> None:
print(f'Send {message} to {phone}')
if __name__ == '__main__':
notification_email = Email()
notification_email.send("Hello", "[email protected]")
notification_sms = SMS()
notification_sms.send('Hello', '+88017243....')
However, there is a potential issue with the current implementation. In the Notification class, the send method takes two parameters, message, and email, while the SMS class takes message and phone. This inconsistency means that code that expects to interact with an object of type Notification may not work correctly when given an object of type SMS.
To rectify the inconsistency and ensure adherence to the Liskov Substitution Principle, we can update the code to ensure that both Email and SMS classes implement the send() method and are substitutable for the Notification base class.
领英推荐
from abc import ABC, abstractmethod
class Notification(ABC):
"""Base Notification Class"""
@abstractmethod
def send(self, message: str) -> None:
pass
class Email(Notification):
"""Send Email using an Email Adress"""
def __init__(self, email: str) -> None:
self.email = email
def send(self, message: str) -> None:
print(f'Send {message} to {self.email}')
class SMS(Notification):
"""Send SMS to a Phone Number"""
def __init__(self, phone: str) -> None:
self.phone = phone
def send(self, message: str) -> None:
print(f'Send {message} to {self.phone}')
if __name__ == '__main__':
email_notification = Email('[email protected]')
email_notification.send('Hello')
sms_notification = SMS('+88017243....')
sms_notification.send('Hello')
It seems that both the Email and SMS classes are proper substitutes for base class Notification.
Now, let's consider a scenario where we have a third class, Slack, that is derived from Notification and is supposed to send messages through the Slack messaging platform. To implement this, we can inherit the base class Notification and add another parameter, api_token, to the constructor, as shown below:
class Slack(Notification):
"""Send Slack Message to a Recipient"""
def __init__(self, recipient_id: str, api_token: str) -> None:
self.recipient_id = recipient_id
self.api_token = api_token
def send(self, message: str) -> None:
print(f"Sending '{message}' to '{self.recipient}' using this {self.api_token} via Slack")
In summary, the Liskov Substitution Principle is an important principle in object-oriented programming that ensures that derived classes can substitute their base classes without causing any issues or breaking the code. By adhering to this principle, we can ensure that our software is correct, reliable, and scalable, making it more reusable and extensible.