What is an example of the Liskov Substitution Principle?

Free Coding Questions Catalog
Boost your coding skills with our essential coding questions catalog. Take a step towards a better tech career now!

Example of the Liskov Substitution Principle

The Liskov Substitution Principle (LSP) is one of the foundational principles in object-oriented programming and part of the SOLID principles. LSP states that objects of a superclass should be replaceable with objects of a subclass without affecting the correctness of the program. In simpler terms, if class S is a subtype of class T, then objects of type T should be replaceable with objects of type S without altering the desirable properties of the program (e.g., correctness, task performed).

Understanding Liskov Substitution Principle

Key Points:

  • Substitutability: Subclasses should be substitutable for their base classes.
  • Behavior Preservation: The behavior of the program should remain consistent when a subclass replaces a base class.
  • No Strengthened Preconditions: Subclasses should not impose stricter conditions than their base classes.
  • No Weakened Postconditions: Subclasses should not promise less than their base classes.

Practical Example in Python

Let's consider a classic example involving geometric shapes: Rectangle and Square.

Base Class: Rectangle

class Rectangle: def __init__(self, width, height): self.width = width self.height = height def set_width(self, width): self.width = width def set_height(self, height): self.height = height def get_area(self): return self.width * self.height

Subclass: Square

class Square(Rectangle): def set_width(self, width): self.width = width self.height = width # Ensuring square property def set_height(self, height): self.height = height self.width = height # Ensuring square property

Function Utilizing Rectangle

def process_rectangle(rect): rect.set_width(5) rect.set_height(10) assert rect.get_area() == 50, "Area should be 50"

Using Rectangle

rect = Rectangle(2, 3) process_rectangle(rect) # Passes assertion print(f"Rectangle Area: {rect.get_area()}") # Output: Rectangle Area: 50

Using Square (Violation of LSP)

square = Square(2, 2) process_rectangle(square) # Assertion fails print(f"Square Area: {square.get_area()}") # Output: Square Area: 100

Explanation:

  1. Expected Behavior:

    • For a Rectangle with width 5 and height 10, the area should be 50.
  2. Using Rectangle:

    • The process_rectangle function sets the width to 5 and height to 10.
    • The area correctly computes to 50, passing the assertion.
  3. Using Square:

    • The process_rectangle function sets the width to 5, which also sets the height to 5 due to the overridden methods in Square.
    • Then, it sets the height to 10, which also sets the width to 10.
    • The expected area was 50, but the actual area is 100, causing the assertion to fail.

Violation of LSP:

  • The Square class alters the expected behavior of the Rectangle class by enforcing equal width and height. This change leads to unexpected results when a Square is used in place of a Rectangle, violating the Liskov Substitution Principle.

Correcting the Violation

To adhere to LSP, ensure that subclasses do not alter the expected behavior of their base classes. One way to resolve this is by avoiding inheritance in cases where it doesn't make sense.

Using Composition Instead of Inheritance

Instead of having Square inherit from Rectangle, use composition to include a Rectangle within Square.

class Square: def __init__(self, side_length): self.rectangle = Rectangle(side_length, side_length) def set_side(self, side_length): self.rectangle.set_width(side_length) self.rectangle.set_height(side_length) def get_area(self): return self.rectangle.get_area()

Updated Function

def process_shape(shape): if isinstance(shape, Rectangle): shape.set_width(5) shape.set_height(10) assert shape.get_area() == 50, "Area should be 50"

Using Rectangle and Square

rect = Rectangle(2, 3) process_shape(rect) # Passes assertion print(f"Rectangle Area: {rect.get_area()}") # Output: Rectangle Area: 50 square = Square(2) process_shape(square.rectangle) # Passes assertion print(f"Square Area: {square.get_area()}") # Output: Square Area: 50

Explanation:

  • By using composition, Square manages its own behavior without altering the Rectangle class.
  • The process_shape function remains compatible with Rectangle instances.
  • This approach maintains the substitutability without violating LSP.

Additional Example: Payment System

Base Class: Payment

class Payment: def pay(self, amount): raise NotImplementedError("Subclasses should implement this!")

Subclass: CreditCardPayment

class CreditCardPayment(Payment): def pay(self, amount): print(f"Processing credit card payment of ${amount}")

Subclass: PayPalPayment

class PayPalPayment(Payment): def pay(self, amount): print(f"Processing PayPal payment of ${amount}")

Function Utilizing Payment

def process_payment(payment_method, amount): payment_method.pay(amount) print("Payment processed successfully.")

Using Subclasses

credit_card = CreditCardPayment() paypal = PayPalPayment() process_payment(credit_card, 100) # Output: # Processing credit card payment of $100 # Payment processed successfully. process_payment(paypal, 200) # Output: # Processing PayPal payment of $200 # Payment processed successfully.

Explanation:

  • Both CreditCardPayment and PayPalPayment are subclasses of Payment.
  • They implement the pay method as required.
  • The process_payment function can seamlessly work with any subclass of Payment, adhering to LSP.

Summary

The Liskov Substitution Principle ensures that subclasses can stand in for their base classes without disrupting the behavior of the program. By adhering to LSP, you create more robust, maintainable, and flexible code. Avoid scenarios where subclasses alter the expected behavior of base classes, and consider using composition over inheritance when appropriate.

For a deeper understanding and more examples of the Liskov Substitution Principle and other object-oriented design principles, consider exploring the Grokking the Object Oriented Design Interview course on DesignGurus.io.

Happy Coding!

TAGS
Coding Interview
CONTRIBUTOR
Design Gurus Team
-

GET YOUR FREE

Coding Questions Catalog

Design Gurus Newsletter - Latest from our Blog
Boost your coding skills with our essential coding questions catalog.
Take a step towards a better tech career now!
Explore Answers
How to crack a code interview?
How do Apple train their employees?
What is the goal of system design interview?
Related Courses
Image
Grokking the Coding Interview: Patterns for Coding Questions
Grokking the Coding Interview Patterns in Java, Python, JS, C++, C#, and Go. The most comprehensive course with 476 Lessons.
Image
Grokking Data Structures & Algorithms for Coding Interviews
Unlock Coding Interview Success: Dive Deep into Data Structures and Algorithms.
Image
Grokking Advanced Coding Patterns for Interviews
Master advanced coding patterns for interviews: Unlock the key to acing MAANG-level coding questions.
Image
One-Stop Portal For Tech Interviews.
Copyright © 2025 Design Gurus, LLC. All rights reserved.