This submit is an element 3 of a collection on the SOLID rules.
You will discover the second submit here.
Earlier than we delve into the reasoning of this precept and the way it matches in with the final two rules, let’s take a look at the definition.
The Liskov substitution precept is formally outlined as:
Let ϕ(x) be a property provable about objects x of sort T. Then ϕ(y) ought to be true for objects y of sort S the place S is a subtype of T. Supply: Barbara Liskov
Let’s face it, this is unnecessary to the fashionable software program engineer.
Right here’s a less complicated definition:
It ought to be attainable to interchange an occasion of a superclass with an occasion of a subclass with out inflicting breaking modifications.
Say you might have a subclass which derives from a base class/superclass (inheritance). Let’s say you make some modifications to the subclass reminiscent of change of parameter worth varieties and maybe additionally the return sort. On this case you’ll have violated the LSP precept as a result of changing an occasion of the superclass with an occasion of the subclass would result in breaking modifications. The code that depends upon the bottom class would count on a return sort of str
for instance however once you substitute the occasion with the subclass, it returns an int
. This is able to might trigger the code to crash or increase different errors.
Briefly, the habits of the bottom class should conform to the habits of the superclass. Typically, the perform signature (perform parameters) and return sort have to be unchanged within the subclass.
The principle function of this precept is to make sure that previous codebases don’t break when new code is launched. Moreover, it ensures versatile code.
Let’s take a look at a easy instance. We alter the situation barely from earlier posts by contemplating a automobile somewhat than a automobile dealership:
The Automotive
class defines a automobile. We initialize it with a reputation, the variety of gears, the pace and the present gear place. The changeGear
perform permits altering of gears whereas the speed up
perform will increase the pace of the automobile by 1. If the gear is within the impartial place N
we do not change the pace however inform the person as a substitute.
Fairly easy.
Let’s say we wish to mannequin a SportsCar
additionally. We make it inherit from the bottom class Automotive
. At initialization we additionally outline a turbos
variable which is an inventory exhibiting what turbo ranges the automobile helps. Due to the habits change we have to outline a brand new acceleration perform that takes turbo
as a parameter. The pace
is elevated by the turbo quantity as a substitute of 1
so the sports activities automobile can speed up quicker.
Within the __main__
perform we outline a standard automobile.
Right here’s the issue:
If we attempt to substitute the Automotive
occasion this with an occasion of a SportsCar
it causes the code to interrupt since speed up
in SportsCar
expects a turbo
argument.
By LSP, changing the above shouldn’t give an error and the code ought to perform as regular.
There are two methods to go about this.
A easy resolution can be to interchange the turbos
variable with a turbo
variable having a set worth. And eradicating the parameter turbo
from the speed up
perform like so:
As you’ll be able to see, the perform signatures are actually instantly equivalent to the bottom class perform signatures. This implies we are able to substitute the Automotive
code within the __main__
perform with SportsCar
with out code breakage. Yay!
Nevertheless, if you happen to discover we have now a set turbo worth 2
on this case.
What if we would like the person to outline the turbo worth prefer it was attainable earlier than?
This requires utilizing an summary class. On we go!
The difficulty is the way in which we have now modelled the automobiles. To make the code above conform to the LSP and have the performance of turbo selection we should create an summary base class Automotive
. Then we create two separate subclasses that inherit from it specifically: SportsCar
and RegularCar
. The diagram illustrates this:
It’ll make extra sense with the code:
We remodel Automotive
to an summary class utilizing the ABC
module. The small print of this should not vital. The init
perform is annoated with @abstractmethod
to indicate an summary perform. This ensures {that a} Automotive
can’t be instantiated. Solely lessons that inherit from this may be instantiated.
Subsequent, we create two lessons that inherit from Automotive
:
RegularCar
indicating a standard automobile with out turboSportsCar
indicating a sports activities automobile with turbo
The RegularCar
has no extra modifications.
Within the SportsCar
class we are able to make the modifications we need. We outline the turbos
array and the turboAccelerate
perform containing the additional turbo
parameter.
On this case, altering the perform signature in SportsCar
shouldn’t be violating the LSP. Why? As a result of the bottom class Automotive
is summary so it can’t be instantiated.
If it can’t be instantiated, it can’t be changed.
On this submit we seemed on the Liskov substitution precept and what it means.
We noticed an instance violating the precept and clear up it utilizing two strategies.
LSP helps make code versatile and prevents points when previous code is prolonged with new code. LSP ensures that habits of code stays the identical throughout each new and previous codebases, leading to code that’s much less liable to breakage.
General, code robustness will increase because of this.
This submit was a bit extra concerned than earlier posts particularly since we approached the issue in a roundabout manner. I needed to discover an fascinating situation that elevated complexity barely. I hope you loved the content material!