Hello again everyone, this time I am here to tell this interesting topic and for sure we’ve all heard a lot: about “inheritance”. Yes folks, let’s talk about the more than punished inheritance in OOP. Let’s see if it really is as bad as they say use it and why, and we’ll see why we often hear that favor the composition instead of inheritance.
The post is divided into three parts, first an explanation of inheritance, then an explanation of the composition and finally a comparison of both. So we are going to start right away as there is no time to lose!
Let’s start with the definition: Inheritance is when an object or class is derived based on another object or class, using the same characteristics or behavior. This is a mechanism for reusing code to allow independent extensions of the original software through public classes and interfaces.
Well, do not worry if it sounds a little Chinese, you will understand the development that we will be doing. But let me ask you to remember that of independent extensions.
To simplify this definition and adjust the most of what should be the inheritance going to do an exercise in abstraction and let’s say that the inheritance is where there is a relationship between the parent and child this relationship is unidirectional to the parent class. Let us take an example to see it better:
The simple Bicycle would be the superclass, and specific types below, we would say they are subclasses. It is the super type or abstraction is the superclass of subtypes or concretions. In addition we say that a road bike is always a bike, but nevertheless, a bike does not have to be always a Road Bike, it can be of any particular type. This means that it is unidirectional, the son is a particular kind of what the father is.
In 95% of cases you use inheritance, if you are not thinking the right questions you’re going to use it badly
If we go to the Greek roots where Poly = Many & Morph = forms
This property of polymorphism is one of the major powers of Inheritance, which means that any child class can can become a parent class, it’s the ability in programming to present the same interface for differing underlying forms.
It allows us to abstract concrete object we use and work with super class.
The relationship of “being” vs “have”
The connection of being in a relationship is stronger than we think, because it has to be for life, what does this mean? We can see better with an example:
You love to run, and we could say that “you are a runner,” but of course, it is possible that when you have 10 grandchildren and 80 years old you prefer to spend your time photography and stop being a runner. Well there you have a false relationship “is a runner”.
It would have been a mistake to raise the class that represents your person as inheritance runner because you are not a runner for life (sorry, and that I too like to run). Just at the time of your life you had a role. And I ask you to remember again, this time, the verb “have”.
Why so much emphasis on the meaning of “to be or not to be” in the inheritance? because it really is necessary to consider this and much inheritance had not caught a bad name before using it if all we had raised that question in the way that I commented above.
Advantages of inheritance
The bad reputation of inheritance is not because it is bad tool, it is because in 95% of cases you will use inheritance, and you are going to misuse it. If you do not ask the right questions. Because inheritance coaxes. Yeah yeah, it seduces you with its benefits, and hides dark side, and has all these advantages:
- Inheritance is attractive because it allows to reuse code in a fast, simple and obvious way.
- It is powerful because it allows me to play with polymorphism with ease.
- Inheritance allows me to overwrite methods, so if something is not exactly as I hope I can always change it if necessary, so it is versatile.
- In Inheritance using something like design pattern Template Method allows me to create abstract classes that make them inherit me to stay a guided created template development, saving time and being a simple guided development.
They are a lot of advantages that push us to use inheritance in our first arguments and they are, in a sense, true. But at some point they will turn against you, with all his strength.
Alert! When inheritance turns against you
Experience in many projects, and many developers have shown. There are more reasons that can lead you to use inheritance at first, but these are the ones we first come to mind. Let’s see why turn against us these “candies”.
The main reason is pretty obvious though not enough. In a project that is part of an agile development process where requirements are constantly changing and are not at all under control, it is impossible to make assumptions like “this screen will always have to do this”, “this response server always has 4 listings “. Erase from your mind the word always, always guide wrongly in our minds “is a” and that guides inheritance.
In a development task where everything changes, inheritance can be waived at any time.
Thus in the early stages of the project, which is precisely where we have more uncertainty, it is virtually impossible to attempt to model behavior based on patterns that can be considered constant , because whether we like it or not, everything is subject to change.
For that reason, if we started using inherited behaviors, although we can a priori achieve rapid and robust results at some point will start to happen things that I categorize with names like these, “the feast of the override” “the barrage of inherited methods useless “,” inheritance of 7 levels, “” the want to inherit and cannot because I am subject to another legacy “and a lot of very fun drawbacks that will mess our code with change, and change is a matter of time .
For the problem of problems, well, it is wrong to use inheritance, that is, use inheritance in place and inappropriate time. In fact do that is the closest thing there is to mortgage your software: at first everything is very nice and everything works, but when you start to pay interest … Ouch! Poor you.
Misusing inheritance is the closest thing there is to mortgage your software
But thanks to the evolution of software engineering and after giving us many times face to face with the Inheritance we have realized that there is another way.
The definition goes on to say something like composition means we have an instance of a class that contains instances of other classes that implement the desired functions.
That is to say, we are delegating tasks that we send to make that piece of code that knows them. The code running that particular task is only on that piece and all the delegate it to perform this task. Therefore we are reusing code again.
Let’s see a pattern as in this case:
In this case we say that the car is composed of Engine, Chassis, Tyres, Wheels, seat belts, windshield… that is, the car has used items to make all the functions you can perform. Delegate the responsibilities to collaborators.
Humans think of a solution to a problem in parts and components and it would be impossible to solve a complex problem without breaking it into small modular solution.
For ex. For manufacturing a Car we can not carve It of Truck. Like a statue is carved out of rock.
Car is simply Composed of Engine, Chassis, Body and other parts. Which are manufactured in different places and then are assembled into a single unit on assembly line.
Car assembly line is a typical Example of Composition
In the composition, we delegate responsibilities to collaborators and assemble those products at one place.
Do you remember “being” in the context of the role of runner? You had the role of runner, i.e., it was a quality of your person at that time. What applies in that case therefore also is the composition.
In this case, the car itself is not tied to anything that says you have to use some specific tires on their wheels as could happen in the inheritance for example. The wheels are in fact a modular and interchangeable piece that interacts with the car through an interface. But the wheels know how to be wheel and tire which suits them. It is their work.
This way of designing allows our software to be much more flexible in programming time and even at run-time.
Everything seems to favor composition, is not it? Well it is not that easy, something must be bad … Let’s see a table that makes a comparison.
As we can see, based on composition design it requires much more time. It is a more thought off and most pampered software, which requires a more concrete more classes that do things
Do you remember the principle of single responsibility? Well, that is, many parts interacting with each other, where each has one and only one task that is its reason to exist.
Making use of composition we can choose whether we will have 0, 1 or N elements that interact to make derived class. This is very versatile run-time because we can even make an object that no longer had a role to have, for example.
This causes in turn the composition into play the creation / destruction of elements within the composite object. This does not exist for example in inheritance because the object already has what is given and what can be implemented by extension.
Using polymorphism in the composition
And here’s the worst of the composition, but do not panic, we can fix it. The composition itself is not polymorphic. This was expected, but there is a very powerful solution to this: What if we make our composite objects implement the interfaces that we want?
Effectively! With the use of interfaces, we can make our composite objects to impersonate the way we come well. And what’s better, you can implement multiple interfaces at any time or stop implement many more versatility than heredity, without being tied to nothing but the methods that implement this particular interface.
With the use of interfaces we get to bring polymorphism in the world of composition.
Here is an example:
As you can see MainActivity, which can be a seen either in Android, has a functionality that comes given by an element containing and not inherit anything, and the way it has to tell the rest of the world who know how to navigate it is using the interface NavigationInterface.
If you cease to have that quality, you would only have to stop implement the interface and not use the object or delete it. If this were Inheritance, and we had two levels of inheritance what if I no longer want or need to have the functionality of the first level but I need the second? As you can see, the second level of inheritance is strongly coupled to the first and cannot have the second without the first.
Besides, what would have happened the first and second level change for our needs and more classes depend on them? All that cause failures, side effects.
However, in this case, as we have navigation functionality, we could assign and remove other following the same strategy without other classes may be affected by the change.
Changing the behavior at runtime
Let’s go further: imagine the NavigationDelegate is not a concrete implementation but is an interface in turn. This would allow us to use a Strategy pattern to insert changed even at runtime the specific navigation we want at all times.
Perhaps we are interested at a time event block back, and there is an implementation of the interface NavigationDelegate we allocate as it suits our composite object. Wonderful is not it?
So to prevent any confusion, we talked about two interfaces:
- The first gives polymorphism our composite object that was lost when using composition, and in turn serves as “a declaration of qualities” that can be our object compound, that is, that defines what is capable of.
- The second gives our object composed the flexibility to change who will implement the specific task at any time.
When inheritance makes sense
Well, if you’re still determined to use inheritance in certain cases, let’s see what cases has no place!
- If we have two classes directly related that are based on each other and belong to the same logical domain, and are sure that they will not cross unwanted borders (e.g. neither they nor any extension will package), you can opt for a relationship inheritance.
- If the subclass is and will always be something based on the superclass and also the implementation of the superclass is appropriate and even necessary for the subclass, you can apply inheritance without fear of making mistakes.
- If besides what you just read, the subclass is a candidate only add new functionality and not to overwrite anything, you’re on the right track and Inheritance is welcome.
Anything that goes against one of these cases should make you hesitate to apply inheritance.
Domain Modeling (How not to abuse Inheritance)
If you notice, all the premises are usually enforced in a fairly common framework: business objects, entities, value objects and other objects of this kind are likely to be modeled inheritance relationships.
Still I recommend you to think well your inheritance relationships. By the way, it does not hurt to remember what the logical domain is from time to time.
Another sensitive case modeling using inheritance can be the development of frameworks, SDKs, although this has its supporters and detractors. Even modeling relationships based on Inheritance, we cannot abuse it.
The Android framework is a clear example of abuse of inheritance relationships. I am now devoting to developing an SDK and in my opinion I like the freedom it gives leave the composition to bind the client your framework to an inheritance relationship.
But this as I said, even as a field susceptible modeled with inheritance at first, it gives rise to a long debate, because still present many of the drawbacks already studied.
Cases of misuse of inheritance
After seeing cases which could have accommodate legacy, let’s see something that is more interesting if possible: examples of some common cases in which we strive to get inheritance for some strange reason, and it has no place:
System behavior modeling as objects representing state model
For example: a use case modeling behavior, not status, and do not have to inherit a base case that has methods that supposedly going to use all use cases because it is very likely that this is not so .
This is a common mistake that is repeated at the beginning of many software designs. We too complex and very low level in early stages of project decisions.
I cannot make a class BaseRequest a method getJSON () to write my JSON object. With that I’m assuming that all my Request will be JSON, and if I have to use a sometime multipart format [form + image], the consistency of my system would be compromised because it cannot inherit from this request, and I would be forced to create another request type.
I’m taking a decision at the beginning of the project that is not at all clear and is tying my development to take a road not if that should follow. Therefore I am leaving flexibility that would give me in that case a compound object, which gives me the opportunity to delay decisions of such a fine grain until the last moment.
Imagine that necessarily have to make a decision of this kind for some reason, following the path of the composition, will have the great advantage that the changes will be limited and under control, at least much more than the inheritance, which any decision wrong and subsequent redesign will cause some side effects involve changes in many fewer pieces of code.
Designs Template Method
Similarly happens with the designs in plan Template Method. It is very common to create totally unnecessary cycles of life through misapplied Inheritance, which initially we thought that they facilitate the development, but ends up turning any modification nightmare…
Is it really necessary to create a flow of execution or life cycle to the elements? In most cases not. And if it were, is it really the solution Inheritance?
Please note the following: abstracting behavior of system components early in the design is one of the most complex tasks of software engineering , and create an inheritance relationship is nothing more than create an abstraction of something that will always be thereby. Really you worth risking so much?
Abstracting behavior early in the design is one of the most complex tasks
The answer is probably no. But if still you are wrong, as we all make mistakes, and you end up in the “mess” of Inheritance , pay attention to the following points because they can make the you detect sooner that inheritance has been applied badly.
How to detect that you are using bad inheritance.
- When Overrides begin to grow and multiply by your code exponentially and sometimes under compulsion and without much sense … Something smells bad!
- If the relationship “being” has been broken for some reason … bad business!
- If your code when it grows by extension, requires modifications of Super Classes, and also tend to always be the same base classes that are playing … Very bad!
- If the levels of inheritance begin to be many, you lose by pulling the thread and side effects begin to manifest … It’s happening to you Mate!
So if you ever suspect any of these points, check eye close to that code. And if it becomes manifest in some way similar, give cane to redesign that part, because the sooner you put measures and root cuttings, the easier it will be. And remember this time go the way of the composition.
I do not have much to add a conclusion that does not stop being a personal opinion and I have already said somewhere. “Inheritance is not bad!!” In fact it may be the solution you need at a particular time.
The problem is that Inheritance is very bad if misused. And as in most of the systems we develop, by nature of change, it is very easy to fall into bad… it is very likely to turn against you and the benefits are nothing compared to their problems in the future.
So just we are saying, when in doubt… do not hesitate! Favor composition over inheritance..
What do you think about this topic? Do you use more inheritance or composition? Leave your opinion in the comments
Inheritance vs Composition — Have clear the weakest link!
Originally published at www.geeksprogramming.com on December 20, 2016.