Liskov’s Substitution Principle

Samyak Moon
3 min readJan 12, 2024

--

In the previous blog we learnt about Open/Closed Principle. In this story we will cover Liskov’s Substitution Principle(LSP) which is one of the five principles of Object-oriented programming known as SOLID.

Barbara Liskov gave the Liskov Substitution Principle which is as follows

Subtypes must be substitutable for their base types without altering the correctness of the program.

In simple way, This principle states that objects of a superclass should be replaceable with objects of a subclass without affecting the correctness of the program. This principle is an extension of the Open/Closed principle.

Let’s say, If you have a class A and another class B that extends(inherits from) A, you should be able to use an object of class B wherever you could use an object of class A, and the program should still work as expected.

This principle encourages the creation of class hierarchies where subclasses can be easily substituted for their parent classes without causing any issues. By doing this, this principle promotes flexibility and maintainability in the code.

Let’s say in an E-commerce application, you have different discount types for each Product.

Discount.java

Discount is an abstract class that serves as the base for various discount types. It declares an abstract method apply(double) that must be implemented by its subclasses.

abstract public class Discount {
abstract double apply(double originalPrice);
}

FixedAmountDiscount.java and PercentageDiscount.java

Two concreate subclasses, FixedAmountDiscount and PercentageDiscount, extends the Discount class. Each provides a specific implementation for the apply method defining how the discount is applied to the original price.

Both subclasses honor the contract established by the base class ensuring that they can be substituted for instances of the base class (‘Discount’) without altering the behavior expected from the apply method.

public class FixedAmountDiscount extends Discount{

private double amount;

public FixedAmountDiscount(double amount){
this.amount =amount;
}
@Override
double apply(double originalPrice) {
return originalPrice-amount;
}
}
public class PercentageDiscount extends Discount{

private double percentage;
public PercentageDiscount(double percentage){
this.percentage = percentage;
}
@Override
double apply(double originalPrice) {
return originalPrice-(percentage/100)*originalPrice;
}
}

Product.java

This class represents a product in the e-commerce application. The applyDiscount method takes a Discount object as a parameter and applies the discount to the product’s price by invoking the apply method. This is a key aspect that follows to LSP — any subclass of Discount can be used interchangeably.

public class Product {
private String name;
private double price;

public Product(String name,double price){
this.name =name;
this.price = price;
}

public String getName() {
return name;
}

public double getPrice() {
return price;
}

public void applyDiscount(Discount discount){
this.price = discount.apply(price);
}
}

Main.java

In the main class, The applyDiscount method of the Product class is called with instances of both discount types(PercentageDiscount and FixedAmountDiscount). This showcases that both PercentageDiscount and FixedAmountDiscount can be seamlessly substituted in place of the generic Discount class.

public class Main {
public static void main(String[] args) {
Product laptop = new Product("Laptop",100.0);
Discount percentageDiscount = new PercentageDiscount(10);
laptop.applyDiscount(percentageDiscount);
System.out.println("After 10% discount: Rs."+laptop.getPrice());

Discount fixedAmountDiscount = new FixedAmountDiscount(50);
laptop.applyDiscount(fixedAmountDiscount);
System.out.println("After Rs.50 discount: Rs."+laptop.getPrice());
}
}

The code follows the Liskov Substitution Principle by establishing a common base class (Discount), which is then extended by concrete subclasses (FixedAmountDiscount and PercentageDiscount). Instances of these subclasses can be used interchangeably where a Discount is expected, without causing any issues or altering the expected behavior.

Conclusion

Liskov’s Substitution Principle plays a vital role in creating maintainable and flexible code structures, allowing for easy substitution of subclasses and enhancing the overall design and extensibility of object-oriented systems. By following LSP, developers can build robust and adaptable software solutions that stand the test of time.

--

--