DEV Community

Cover image for SOLID Principles: Liskov Substitution Principle (LSP)
Amburi Roy
Amburi Roy

Posted on

SOLID Principles: Liskov Substitution Principle (LSP)

🪨 SOLID Principles

SOLID is a list of 5 software engineering principles. It is a meta acronym where each letter corresponds to another acronym:

Without any further ado, let's jump into today's topic:

Liskov Substitution Principle (LSP)

The Liskov Substitution Principle (LSP) is one of the SOLID principles of object-oriented programming.

Definition: Objects of a superclass should be replaceable with objects of a subclass without affecting the correctness of the program.

  • Maintain behavioral consistency between base and derived classes.
  • Enable subtype polymorphism for flexibility and code reuse.
  • Encourage the use of abstract classes, interfaces, and inheritance for better organization and reusability.
  • Facilitate software extension without modifying existing code.
  • Reduce the risk of introducing bugs when extending the system.
  • Support polymorphic behavior, allowing different classes to share a common interface.
  • Contribute to robust, maintainable, and extensible software and SOLID compliance.

Bad Example:

class PaymentGateway {
    public function processPayment($amount) {
        // Common payment processing code
    }
}

class CreditCardPaymentGateway extends PaymentGateway {
    public function processPayment($amount) {
        if ($this->validateCreditCard()) {
            parent::processPayment($amount);
            // Payment successful using credit card
        } else {
            // Payment failed: Invalid credit card
        }
    }

    public function validateCreditCard() {
        // Code to validate credit card
    }
}

class PayPalPaymentGateway extends PaymentGateway {
    public function processPayment($amount) {
        // PayPal-specific payment processing code
    }
}

function completePayment(PaymentGateway $gateway, $amount) {
    $gateway->processPayment($amount);
}

$creditCardGateway = new CreditCardPaymentGateway();
$paypalGateway = new PayPalPaymentGateway();

completePayment($creditCardGateway, 100);
completePayment($paypalGateway, 50);
Enter fullscreen mode Exit fullscreen mode

Here, the CreditCardPaymentGateway class violates the Liskov Substitution Principle. When we try to use it as a substitute for the PaymentGateway superclass, it changes the behavior of the processPayment method by adding credit card validation logic. This makes it difficult to predict how the program will behave when using different payment gateways, breaking the principle.

Good Example:

interface PaymentGatewayInterface {
    public function processPayment($amount);
}

class PaymentGateway implements PaymentGatewayInterface {
    public function processPayment($amount) {
        // Common payment processing code
    }
}

class CreditCardPaymentGateway implements PaymentGatewayInterface {
    public function processPayment($amount) {
        // Credit card payment processing code
    }

    public function validateCreditCard() {
        // Code to validate credit card
    }
}

class PayPalPaymentGateway implements PaymentGatewayInterface {
    public function processPayment($amount) {
        // PayPal-specific payment processing code
    }
}

function completePayment(PaymentGatewayInterface $gateway, $amount) {
    $gateway->processPayment($amount);
}

$creditCardGateway = new CreditCardPaymentGateway();
$paypalGateway = new PayPalPaymentGateway();

completePayment($creditCardGateway, 100);
completePayment($paypalGateway, 50);
Enter fullscreen mode Exit fullscreen mode

Here, we introduce an PaymentGatewayInterface interface that all payment gateway classes implement. Each class implements the processPayment method as required by the interface. This adheres to the Liskov Substitution Principle because we can freely substitute any payment gateway object in the completePayment function without affecting the correctness of the program.

Wrap-Up!

Liskov Substitution Principle (LSP) is a fundamental principle in object-oriented programming, and it is generally advisable to follow it in most cases. However, there may be exceptional situations, such as performance optimization or dealing with highly complex real-world models, where you need to carefully consider whether strict adherence is practical or whether temporary deviations are warranted for specific reasons. Always document and communicate any intentional deviations from LSP to ensure the maintainability and understanding of your codebase.

Top comments (0)