Common Practices: Inheritance
Table of Contents
Introduction
Inheritance apparently takes a lot of work off our shoulders, but because of the dependencies that inheritance creates, it takes a fair amount of attention to decide when inheritance makes sense and when it should be avoided.
On the one hand, inheritance makes it effortless and cheap to make changes that affect all subtypes, which is wonderful when it comes to a bug fix. If something needs to be extended, this is also easy with inheritance (hooray! We work according to the open-close principle!). On the other hand, it cannot be denied that this is only bought by a very strong dependency. Each subtype is directly related to its parent type. Another aspect is that it is not always clear what changes will come. Here it can suddenly become expensive, if an entire class structure must be adapted.
If you don't know the future, then it is often easier to use the I-have or I-can relationship instead of the I-am-one relationship. This costs more implementation time because one must create many interfaces and distribute the responsibilities partly on several classes. However, these relations are usually cheaper with an uncertain future.
To be or not to be a subtype
In inheritance, the following must always be satisfied to allow the replacement of objects:
If for the class Foo there is the specialization FooBar, programs and their behavior using Foo must remain unchanged when Foo is replaced by FooBar. Conversely, this means that FooBar is only a subtype of Foo if the replacement of Foo by FooBar does not cause any changes in the behavior of the users of Foo.
Don’t waste your time
If you have understood everything, or if you are familiar with Barbara Liskov's substitution principle, then skip the rest of the chapter. Everything is clear then proceed with https://ekvip.atlassian.net/wiki/x/B4AcYg
Explanation using a bad example
For a better understanding, here is an example where the required principle is violated:
We have a rectangle and a square, in mathematics, the square is a specialized form of the rectangle (every square is also a rectangle).
In the example, you can see very well that square must not be a subtype of rectangle. Because in the rectangle, the sides a and b can be changed independently of each other, whereas in the square the side length always changes together. In the example, the client-object of rectangle would change its behavior if it got a square object instead of a rectangle object. This violates the principle that a subtype is only a subtype if replacing the base type with a subtype does not change the behavior.