Last week we looked at the second of the SOLID design principles – the Open-Closed principle – in more detail. This week we’ll cover the next one in the acronym: the Liskov Substitution principle (LSP).
If you missed the previous posts in this sequence, you can find them here:
- SOLID Design Principles Part 1 – Single Responsibility Principle
- SOLID Design Principles Part 2 – Open-Closed Principle
The Liskov Substitution Principle (LSP)
“Derived classes must be usable through the base class interface without the user knowing the difference”.
Wherever a superclass is needed, an instance of a derived class should be able to be substituted. That requires that subclasses must behave in the same way as the superclass. To achieve that, our subclasses need to follow these rules:
- Don’t have any stricter validation rules on input parameters than the superclass has.
- Apply at least the same rules to all output parameters as applied by the superclass.
The Liskov Substitution principle is described in detail in: Barbara Liskov and Jeanette Wing, “A Behavioral Notion of Subtyping”, ACM Transactions on Programming Languages and Systems, Volume 16, No 6, November 1994, pages 1811-1841. You can read the whole paper.
Quoting from the abstract of the paper: “The use of hierarchy is an important component in object-oriented design. Hierarchy allows the use of type families, in which higher-level super-types capture the behaviour that all of their subtypes have in common. …The relationship should ensure that any property proved about super-type objects also holds for subtype objects…”
Simply put, the subclass objects should behave in the same way as superclass objects as far as anyone using the superclass objects can tell. We should be able to substitute an object of any subclass in a program that expects a superclass object, and the program should still behave reasonably. It extends the Open-Closed Principle by focusing on the behaviour of a superclass and its subclasses.
EventLogger Example
In last week’s tip on the Open-Closed Principle, we created a NotifyingEventLogger
class that extended our EventLogger
class to send an email or SMS notification when logging an event.
Let’s see the Liskov Substitution principle in action. When we require an EventLogger
object, we can either create an instance of the EventLogger
class or an instance of the NotifyingEventLogger
class, e.g:
EventLogger logger = new EventLogger(); // OR EventLogger logger = new NotifyingEventLogger(); // the application behaves as expected // whichever instance was created logger.log("A message to be logged");
Collections Example
We use the Liskov Substitution principle all the time when using the Java Collections API. Let’s say that we need a collection of Employee
objects. We could choose the trusted ArrayList
class by using the following code:
ArrayList list = new ArrayList<>();
An ArrayList
works well when it’s a fixed size, but slows down when we need to add (or delete) elements. If we need a collection that’s faster when adding elements, we could choose a LinkedList
as follows:
LinkedList list = new LinkedList<>();
The problem here is that we have to change the type of the collection variable and recompile the code. A better approach would be to use the List
interface which both classes implement:
List list; list = new ArrayList<>(); // OR list = new LinkedList<>();
We could then pass the concrete class type through at runtime by using the Class.forName()
method.
The best approach would be to use the top-level Collection
interface as the compile time type of the collection variable, as follows:
Collection collection;
This would allow us to instantiate an object of *any* concrete class implementing the Collection
interface:
collection = new ArrayList<>(); // OR collection = new LinkedList<>(); // OR collection = new TreeSet<>(); // OR collection = new HashSet<>(); // etc.
This is the beauty of the Liskov Substitution principle!
What’s next?
In next week’s tip, we’ll look at the next principle in the acronym: the Interface Segregation principle (LSP).
As always, please share your comments and questions. If you missed the previous articles, you can find them here: