This article describes what is Liskov Substitution Principle along with code examples in Java. Please feel free to comment/suggest if I missed mentioning one or more important points. Also, sorry for the typos.
In this post, you will learn some of the following:
You may also want to check another code quality principle such as Single Responsibility Principle explained with Java Examples.
Take a look at this paper on Liskov Substitution Principle which provides great details on Liskov Substitution Principle. As per LSP, functions that use references to the base classes must be able to use objects of derived class without knowing it. In simple words, derived classes must be substitutable for the base class. To illustrate LSP, let’s take an example of Rectangle and Square. One tends to establish the ISA relationship, thus, calling Square as a rectangle (Square is a Rectangle). However, there arises a problem (hence, violation of LSP) which shall be demonstrated with the code sample. Take a look at code illustration below to understand LSP in detail.
Pictorially, the comic strip given below should help you understand the Liskov Substitution Principle in an easier manner. Once a class follows inheritance rule, it should be able to be substituted in place of the base class without any change required in the code using the reference of the derived class. This is unlike the comic strip below where a substitute is unable to perform activities of a music teacher for which he got substituted.
Liskov Substitution principle is popularly explained using Square and Rectangle example. Let’s assume we try to establish ISA relationship between Square and Rectangle. Thus, we call “Square is a Rectangle”. Below code represents the relationship.
/** * Rectangle * @author Ajitesh Shukla */public class Rectangle { private int length; private int breadth; public int getLength() { return length; } public void setLength(int length) { this.length = length; } public int getBreadth() { return breadth; } public void setBreadth(int breadth) { this.breadth = breadth; } public int getArea() { return this.length * this.breadth; } }
Below is the code for Square. Note that Square extends Rectangle.
/** * Square class; Square inherits from Rectangle; * Represents ISA relationship - Square is a Rectangle * @author Ajitesh Shukla */public class Square extends Rectangle { @Override public void setBreadth(int breadth) { super.setBreadth(breadth); super.setLength(breadth); } @Override public void setLength(int length) { super.setLength(length); super.setBreadth(length); } }
Look at the calculateArea method in the code below. One should note that as per the definition of Rectangle, the following must always hold true given the data below:
In case, we try to establish ISA relationship between Square and Rectangle such that we call “Square is a Rectangle”, below code would start behaving unexpectedly if an instance of Square is passed. Assertion error will be thrown in case of check for area and check for breadth, although the program will terminate as the assertion error is thrown due to failure of Area check.
/** * The class demonstrates the Liskov Substitution Principle (LSP) * * As per the principle, the functions that use references to the base classes must be able to use objects of derived class without knowing it. * Thus, in the example shown below, the function calculateArea which uses the reference of "Rectangle" should be able to use the objects of * derived class such as Square and fulfill the requirement posed by Rectangle definition. * * @author Ajitesh Shukla */public class LSPDemo { /** * One should note that as per the definition of Rectangle, following must always hold true given the data below: * 1. Length must always be equal to the length passed as the input to method, setLength * 2. Breadth must always be equal to the breadth passed as input to method, setBreadth * 3. Area must always be equal to product of length and breadth * * In case, we try to establish ISA relationship between Square and Rectangle such that we call "Square is a Rectangle", * below code would start behaving unexpectedly if an instance of Square is passed * Assertion error will be thrown in case of check for area and check for breadth, although the program will terminate as * the assertion error is thrown due to failure of Area check. * * @param r Instance of Rectangle */ public void calculateArea(Rectangle r) { r.setBreadth(2); r.setLength(3); // // Assert Area // // From the code, the expected behavior is that // the area of the rectangle is equal to 6 // assert r.getArea() == 6 : printError("area", r); // // Assert Length & Breadth // // From the code, the expected behavior is that // the length should always be equal to 3 and // the breadth should always be equal to 2 // assert r.getLength() == 3 : printError("length", r); assert r.getBreadth() == 2 : printError("breadth", r); } private String printError(String errorIdentifer, Rectangle r) { return "Unexpected value of " + errorIdentifer + " for instance of " + r.getClass().getName(); } public static void main(String[] args) { LSPDemo lsp = new LSPDemo(); // // An instance of Rectangle is passed // lsp.calculateArea(new Rectangle()); // // An instance of Square is passed // lsp.calculateArea(new Square()); } }
Given the above code, what is the problem with Square-Rectangle ISA relationship?
Following are some of the code quality characteristic which is represented by Liskov Substitution Principle.
In recent years, artificial intelligence (AI) has evolved to include more sophisticated and capable agents,…
Adaptive learning helps in tailoring learning experiences to fit the unique needs of each student.…
With the increasing demand for more powerful machine learning (ML) systems that can handle diverse…
Anxiety is a common mental health condition that affects millions of people around the world.…
In machine learning, confounder features or variables can significantly affect the accuracy and validity of…
Last updated: 26 Sept, 2024 Credit card fraud detection is a major concern for credit…