The LSP explained – Architectural Principles
The LSP came from Barbara Liskov at the end of the ‘80s and was revisited during the ‘90s by both Liskov and Jeannette Wing to create the principle that we know and use today. It is also similar to Design by contract, by Bertrand Meyer.Next, let’s look at the formal subtype requirement definition:
be a property provable about objects x of type T. Then,
should be true for objects y of type S, where S is a subtype of T.
In simpler words, if S is a subtype of T, we can replace objects of type T with objects of type S without changing any of the expected behaviors of the program (correctness).The LSP adds the following signature requirements:
- The parameters of methods in subtypes must be contravariant.
- The return type of methods in subtypes must be covariant.
- You can’t throw a new type of exception in subtypes.
The first two rules are tough to violate without effort in C#.
Throwing a new type of exception in subtypes is also considered changing behaviors. You can, however, throw subtyped exceptions in subtypes because the existing consumers can handle them.
The LSP also adds the following behavioral conditions:
Table 3.1: LSP behavioral conditions
OK, at this point, you are right to feel that this is rather complex. Yet, rest assured that this is the less important of those principles because we are moving as far as we can from inheritance, so the LSP should not apply often.
In your subtypes, add new behaviors and states; don’t change existing ones.