Details of Liskov Substitution Principle Example

Liskov Substitution Principle (LSP)

Basically, the principle states that if in an object-oriented program you substitute superclass object reference with any of its subclass objects, it should not break the program.

public class Bird
{
void fly()
{
// Fly function for bird
}
}

public class Parrot extends Bird
{
@Override
void fly()
{

}
}

public class Ostrich extends Bird
{
// can't implement fly since Ostrich doesn't fly
}
  1. If a subclass returns an object that is completely different from what the superclass returns.
  2. If a subclass throws an exception that is not defined in the superclass.
  3. There are any side effects in subclass methods that were not part of the superclass definition.

How do programmers break this principle?

Sometimes, if a programmer ends up extending a superclass without completely following the contract of the superclass, a programmer will have to use instanceof check for the new subclass. If there are more similar subclasses are added to the code, it can increase the complexity of the code and violate the LSP.

Liskov Substitution Principle Example

Now, let’s look at an example in detail.

public abstract class BankAccount
{
public boolean withDraw(double amount);

public void deposit(double amount);

}
public class BasicAccount extends BankAccount
{
private double balance;

@Override
public boolean withDraw(double amount)
{
if(balance > 0)
{
balance -= amount;
if(balance < 0)
{
return false;
}
else
{
return true;
}
}
else
{
return false;
}
}

@Override
public void deposit(double amount)
{
balance += amount;
}
}
public class PremiumAccount extends BankAccount
{
private double balance;
private double rewardPoints;

@Override
public boolean withDraw(double amount)
{
if(balance > 0)
{
balance -= amount;
if(balance < 0)
{
return false;
}
else
{
return true;
updateRewardsPoints();
}
}
else
{
return false;
}
}

@Override
public void deposit(double amount)
{
this.balance += amount;
updateRewardsPoints();
}

public void updateRewardsPoints()
{
this.rewardsPoints++;
}
}
public class InvestmentAccount extends BankAccount
{
private double balance;

@Override
public boolean withDraw(double amount)
{
throw new Expcetion("Not supported");
}

@Override
public void deposit(double amount)
{
this.balance += amount;
}

}

How to avoid violating LSP in the design?

So how can we avoid violating LSP in our above example? There are a few ways you can avoid violating Liskov Substitution Principle. First, the superclass should contain the most generic information. We will use some other object-oriented design principles to do design changes in our example to avoid violating LSP.

  • Use Interface instead of Program.
  • Composition over inheritance
public interface IBankAccount
{
boolean withDraw(double amount) throws InvalidTransactionException;
void deposit(double amount) throws InvalidTransactionException;
}

Conclusion

In this post, we talked about Liskov Substitution Principle and its example, how designers usually violate this principle, and how we can avoid violating it.

--

--

Software Developer, Writer

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store