Liskov substitution principle is a particular definition of a subtyping relation, called strong behavioral subtyping. The LSP is appliceable when there's a supertype-subtype inheritance relationship by either extending a class or implementing an interface.
If client code acannot substitute a superclass reference with a subclass object freely, it would be forced to do
instanceof checks and specially handle some subclasses. If this kind of conditional code is spread across the codebase, it will difficult to maintin.
Some good indicators to identify LSP Violations are:
1. Conditional logic (using the instanceof operator or object.getClass().getName() to identify the actual subclass) in client code
2. Empty, do-nothing implementations of one for more methods in subclasses
3. Throwing an UnsupportedOperationException or some other unexpected exception from a subclass method
For point 3 aboce, the exception needs to be unexpected from the superclasses's contract perspective. So, if our superclass method's signature explicityly specified that subclasses or implementations could throw an
UnsupportedOperationException, then we would not consider it as an LSP violation
Code that adheres to LSP is loosely dependent to each other and encourages code