DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
  1. DZone
  2. Culture and Methodologies
  3. Methodologies
  4. The Liskov Substitution Principle (With Examples)

The Liskov Substitution Principle (With Examples)

Take a look at this breakdown of the Liskov Substitution Principle and how following it ensures clean code that interacts well with itself.

Ajitesh Kumar user avatar by
Ajitesh Kumar
CORE ·
Oct. 17, 16 · Tutorial
Like (37)
Save
Tweet
Share
133.23K Views

Join the DZone community and get the full member experience.

Join For Free

This article describes the Liskov Substitution Principle along with some examples in Java. Please feel free to make comments/suggestions if I missed some important points. 

The following are the key points described in this article:

  • What is the Liskov Substitution Principle (LSP)?
  • Code Samples to Illustrate the LSP.
  • What code quality characteristics are represented by the LSP?

What Is the Liskov Substitution Principle (LSP)?

Take a look at this paper on the Liskov Substitution Principle, which provides a lot of details on it. As per the LSP, functions that use references to base classes must be able to use objects of the derived class without knowing it. In simple words, derived classes must be substitutable for the base class. To illustrate the LSP, let’s take an example of rectangles and squares. One tends to establish the ISA relationship, thus, you can say that a square a rectangle. However, there arises a problem (hence, a violation of the LSP) which shall be demonstrated with the following code sample. Take a look at code illustration below to understand the LSP in detail.

Java Code Samples to Illustrate the LSP

The LSP is popularly explained using the square and rectangle example. Let’s assume we try to establish an ISA relationship between Square and Rectangle. Thus, we call “Square is a Rectangle.” The code below 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);
    }
}

The code below represents the function which has Rectangle as an argument. 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.

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: 
  • Length must always be equal to the length passed as the input to method, setLength.
  • Breadth must always be equal to the breadth passed as input to method, setBreadth.
  • Area must always be equal to the product of length and breadth.

In this case, we try to establish an ISA relationship between Square and Rectangle such that calling “Square is a Rectangle” in the below code would start behaving unexpectedly if an instance of Square is passed. An assertion error will be thrown in the case of checking for "Area" and checking for "Breadth," although the program will terminate as the assertion error is thrown due to the failure of the 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?

  • The Square class does not need methods like setBreadth or setLength, as the sides of a square are equal. This is wasteful. Imagine of hundreds of thousands of Square objects.
  • The LSPDemo class would need to know the details of derived classes of Rectangle (such as Square) to code appropriately to avoid throwing error. The change in the existing code to take care of the derived class breaks the open-closed principle in the first place.

What Code Quality Characteristic Is Represented by LSP?

The following are some of the code quality characteristics that are represented by the Liskov Substitution Principle.

  • It is only when derived types are completely substitutable for their base types that functions that use those base types can be reused with impunity, and the derived types can be changed with impunity.
  • The LSP is also, at times, termed as “Design by Contract.” Using this scheme, methods of classes declare pre-conditions and post-conditions. The pre-conditions must be true in order for the method to execute. Upon completion, the method guarantees that the post-condition will be true.
  • Design by Contract does influence the declaration of “throws” exceptions, as well as the throwing of runtime exceptions and try/catch in general.
Liskov substitution principle

Published at DZone with permission of Ajitesh Kumar, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Integrate AWS Secrets Manager in Spring Boot Application
  • How To Create a Failover Client Using the Hazelcast Viridian Serverless
  • Intro to Graph and Native Graph Databases
  • OWASP Kubernetes Top 10

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: