This principle suggests that we should be able to replace objects with instances of their subtypes or subclasses without affecting the correctness of the program.
In simpler terms, you should be able to use an object of a child class in place of an object of its parent class without changing how the program behaves.
To demonstrate, we need to ensure that the child class has "is-a" relationship with the parent class. This means the child class must follow all the rules and expectations set by the parent class. By doing this, we maintain consistent behavior and ensure that our program remains reliable and predictable.
Let's refactor our PaymentHandler
class to demonstrate LSP. We will first remove the dependency from security_token
at the parent class level and move it to the child classes, so each payment handler can have its own unique verification method.
Then we'll add new __init__
methods to the child classes to set independent verification methods, isolating the verification logic for each payment handler.
Note: How our new class
CryptoPayment
has a different verification method compared toCardPayment
andPayPalPayment
. This demonstrates that we can substitute different payment handlers without affecting the behavior of theCheckout
class instance.
from abc import ABC, abstractmethod
class Checkout:
def __init__(self):
self.products = []
self.quantity = []
self.price = []
self.status = "pending"
class PaymentHandler(ABC):
@abstractmethod
def pay(self, checkout: Checkout):
pass
class CardPayment(PaymentHandler):
def __init__(self, token: str):
self.security_token = token
def pay(self, checkout: Checkout):
print("Verifying payment with token:", self.security_token)
print("Processing card payment...")
checkout.status = "paid"
class PayPalPayment(PaymentHandler):
def __init__(self, token: str):
self.security_token = token
def pay(self, checkout: Checkout):
print("Verifying payment with token:", self.security_token)
print("Processing PayPal payment...")
checkout.status = "paid"
class CryptoPayment(PaymentHandler):
def __init__(self, token: str):
self.fingerprint_token = token
def pay(self, checkout: Checkout):
print("Verifying crypto payment with fingerprint:", self.fingerprint_token)
print("Processing cryptocurrency payment...")
checkout.status = "paid"
checkout = Checkout()
paypal_processor = PayPalPayment("900913")
paypal_processor.pay(checkout)
crypto_processor = CryptoPayment("0xdeadbeef")
crypto_processor.pay(checkout)