I had problems understanding when / why to implement inheritance and when / why to implement inheritance through the interface. Please carry me as I explain.
Let's say we have a parent class Animal , and we want to extend it with 3 subclasses: Dog , Cat and Mouse .
Suppose all Animals can eat() , sleep() , scratch() and move() . and Dog can pant() . With this knowledge, we will continue to add the first 4 behaviors to the Animal superclass and have Dog , Cat and Mouse extend Animal . We will also add the pant() method to the Dog class, but only the pant() dogs.
Now, what happens if we want to add another method called waggleTail() , but only Cat and Dog exhibit this behavior. We cannot add this behavior to Animal bec, then Mouse also inherits the behavior (and the mouse does not flap its tail). An alternative is to add the waggleTail() method to the Dog and Cat classes, but not to the Mouse class. This approach, however, does not make sense, because we would then violate the DRY principle (do not repeat yourself) by using the waggleTail() method waggleTail() . We want to write each method once and only once.
Perhaps we could solve this problem by creating a new subclass inherited from Animal called TailWagglingAnimal , add the waggleTail() method to this subclass, and then inherit from this Dog and Cat subclass. This sounds reasonable until you realize that there are many other similar anomalies, and we will have to repeat this process again and again for each of them (this will not lead to an expansion of the inheritance hierarchy).
Also, what if we have a specific type of Dog (let's call it "Coton de Tulear") that demonstrates all of Dog other behaviors (for example, suffocating), except that he does not shake his tail. If we have a "Coton de Tulear" inherited directly from Animal , it will not be able to suffocate (). If we inherited it from Dog , it would be able to flap its tail (bec Dog extends TailWagglingAnimal ). If we had Dog extend Animal directly and then create a new subclass called TailWagglingDog (like appose to TailWagglingAnimal ), Cat would not be able to inherit this behavior (so we would need to duplicate the behavior somewhere inside the Cat hierarchy, which violates the DRY principle) .
What should we do?
Based on dozens of threads in stackoverflow (and several OO design books), it was suggested to remove the waggleTail() method from the Dog class and add it to the interface and interface. Let’s call the TailWaggler interface, and then all dogs (except "Coton de Tulear") implement this interface. However, it’s hard for me to understand why / how it is useful.
If you think about it, this means that all 50+ dog loaves (suppose there are 50 dog loaves that should exhibit this behavior) you need to add the TailWaggler tools the keyword in the form of only one species Dog does not exhibit such behavior. Not only does this mean a lot of additional manual work on the part of the programmer (adding TailWaggler tools to the beginning of each class), it means that all descendants should be connected with all the small and minor details of the behavior that they (this would not be so if we would add this behavior to the parent class and extend the parent class). It might be good if we had only a few such cases, but what if we had dozens or hundreds of such cases? Finally, as we add new types of subclasses of dog types, in the end there will be one type of Dog - another that will not demonstrate one of the actions of the parent class of Dog, so this means slowly, but of course, we will need to remove almost all the behavior from the class (parent) Dog and add them to the interface? Then we need to make sure that all subclass implement dozens of different interfaces. It can be assumed that we group all the behaviors associated with this in one interface, but this is only possible if the behavior shown by different dogs is uniform - what if this is not so?)
Thanks!