Liskov substitution principle (LSP): Derived classes must be substitutable for their base classes. -- proposed by Barbara Liskov
LSP sounds the same as substitutability but it goes beyond substitutability; LSP implies that a subclass should not be more restrictive than the behavior specified by the superclass. As you know, Java has language support for substitutability. However, if LSP is not followed, substituting a subclass object for a superclass object can break the functionality of the code.
Textbook
Paradigms → Object Oriented Programming → Inheritance → What
Paradigms → OOP → Inheritance →
Every instance of a subclass is an instance of the superclass, but not vice-versa. As a result, inheritance allows substitutability: the ability to substitute a child class object where a parent class object is expected.
An AcademicStaff
is an instance of a Staff
, but a Staff
is not necessarily an instance of an AcademicStaff
. i.e. wherever an object of the superclass is expected, it can be substituted by an object of any of its subclasses.
The following code is valid because an AcademicStaff
object is substitutable as a Staff
object.
Staff staff = new AcademicStaff();
But the following code is not valid because staff
is declared as a Staff
type and therefore its value may or may not be of type AcademicStaff
, which is the type expected by variable academicStaff
.
Staff staff;
...
AcademicStaff academicStaff = staff;
Suppose the Payroll
class depends on the adjustMySalary(int percent)
method of the Staff
class. Furthermore, the Staff
class states that the adjustMySalary
method will work for all positive percent values. Both the Admin
and Academic
classes override the adjustMySalary
method.
Now consider the following:
- The
Admin#adjustMySalary
method works for both negative and positive percent values.
- The
Academic#adjustMySalary
method works for percent values 1..100
only.
In the above scenario,
- The
Admin
class follows LSP because it fulfills Payroll
’s expectation of Staff
objects (i.e. it works for all positive values). Substituting Admin
objects for Staff
objects will not break the Payroll
class functionality.
- The
Academic
class violates LSP because it will not work for percent values over 100
as expected by the Payroll
class. Substituting Academic
objects for Staff
objects can potentially break the Payroll
class functionality.
Another example
The Rectangle#resize()
method can take any integers for height
and width
. This contract is violated by the subclass Square#resize()
because it does not accept a height
that is different from the width
.
class Rectangle {
...
void resize(int height, int width) {
...
}
}
class Square extends Rectangle {
@Override
void resize(int height, int width) {
if (height != width) {
}
}
}
Now consider the following method that is written to work with the Rectangle
class.
void makeSameSize(Rectangle original, Rectangle toResize) {
toResize.resize(original.getHeight(), original.getWidth());
}
This code will fail if it is called as makeSameSize(new Rectangle(12, 8), new Square(4, 4))
. That is, the Square
class is not substitutable for the Rectangle
class.
Exercises
Is this LSP?
If a subclass imposes more restrictive conditions than its parent class, it violates Liskov Substitution Principle.
True.
Explanation: If the subclass is more restrictive than the parent class, code that worked with the parent class may not work with the child class. Hence, the substitutability does not exist and LSP is violated.