Difference between the IS-A and Liskov Substitution Principle?
Both terms describe the same "concept" in the end.
The Liskov substitution principle tells you: an inheritance relation between to classes B (base) and C (child) is sound when each and any usage of some object of type B ... can be replaced with an object of type C.
This means: B defines an API and a public contract - and C has to uphold these properties, too!
And IS-A amounts to the same thing: that some object of C is also a B.
The "difference" is: the LSP gives you exact rules that you can check. Whereas IS-A is more of an "observation" or expression of intent. Like in: you express that you wish that class C IS-A B.
In other words: when you don't know how to properly use inheritance, IS-A doesn't help you writing correct code. Whereas the LSP clearly tells you that something like:
class Base { int foo(); }
class Child extends Base { @Override double foo(); }
is invalid. According to LSP, you can only widen method arguments, and restrict return values.
int iValue = someBase.foo();
can't be replaced with
int iValue = someChild.foo();
because the foo()
method is widened in its result.
And a final thought: many people think that C IS-A B is the same as just writing down Child extends Base
. Yes. But this only tells the compiler that C extends B. It doesn't mean that the methods you use in C will follow the LSP and thus turn C into a real valid descendant of B.
C IS-A B requires more than "C extends B". To be truly valid, LSP has to be uphold!