Liskov Substitution Principle

What is „Liskov Substitution Principle” (LSP) ?

It is the third rule of the SOLID design rules (it stands for L in SOLID acronym).

Definition

The principle that subclasses should satifsy the expectactions of clients accessing subclass objects through references of superclass type, not just as regards syntactic safety (such as absence of „method-not-found” errors), but also as regards behaviour correctness.
 
         Barbara Liskov

In simpler words, the derived class should only extend the capabilities of the base class and in some sense not change what it has been doing before. This would give us the possibility to use subclasses in place of parent class interchangeably and it should not break the program.

Real-life example

Let’s say we want to implement classes for a duck and an ostrich. Both animals are birds, so at first thought, they can inherit from the parent class called Bird.

public class Bird {
    public void fly() {
    }
}
public class Duck extends Bird {

    @Override
    public void fly() {
        System.out.println("Duck is flying");
    }
}

As is well known, ostriches do not fly, therefore we need to leave fly method empty.

public class Ostrich extends Bird {

    @Override
    public void fly() {
    }
}

UML diagram of our application:

We are forces to leave fly method without any implementation, what means that we do not meet LSP rule.

Such a solution is a very dangerous programming procedure that could be misleading for other programmers. On the other hand, if we don’t do this, we will get a compilation error. This is a sign about an incorrectly designed class hierarchy in our program.

Adding additional class to inherit from for flying birds can help us.

public class Bird {
}
public class FlyingBird extends Bird {
    public void fly() {
    }
}
public class Duck extends FlyingBird {

    @Override
    public void fly() {
        System.out.println("Duck is flying");
    }
}
public class Ostrich extends Bird {
}

Problem with fly method, which was not implemented is gone now. It means that we have proper class hierarchy and we did only extend functionalities which was really needed.

LSP rules also claims that using subclasses inheriting from the same parent should be interchangeable. This requirement is also meet by the program we have written. To prove it, let’s add Pigeon class. Pigeon can fly, that is why it needs to inherit from FlyingBirds class.

public class Pigeon extends FlyingBird {

    @Override
    public void fly() {
        System.out.println("Pigeon is flying");
    }
}

Duck and Pigeon both implement the same functionality, therefore for outside classes there is no difference if Bird or Pigeon object is used.

UML diagram of our application after refactoring:

Why should I follow „Liskov Substitution Principle” ?

Thanks to this rule, the code is loosely dependent to each other, susceptible to expandability and easy to reuse.

Posted in SOLID rulesTags:
Write a comment