Let’s talk about inheritance, a powerful and in the same time overused and misused mechanism in OOP.
The WHAT
So, inheritance is a mechanism which allows one to use the data and behavior of an object (let’s say object X) on a different object (let’s say object Y). This usually happens to extend the functionality of object X into a new object, Y. This Y object is very similar with X, but has at least one change/extension to it. This sounds a bit more complicated than it actually is, so let’s dive in and better understand the concept.
The HOW
Let’s assume you want to model several Car objects. Based on brand and model, each car will have different features available. Also, all car makers need to respect the vehicle construction regulations so that the future cars will be legal on the streets.
In order to create a new car, the minimum a maker could do is to be compliant with the vehicle construction regulations. Let’s assume that apart of the basic features (breaks, head lights, stop lights, turn signal lights, seat belt etc.) each car needs to be equipped with reverse camera, tire pressure monitoring system and emergency stop signals.
So, it makes sense for the makers to include these mandatory features first and afterwards add extra ones for their clients. Let’s see how you could model this in code.
You could create a RegulationCompliantCar class which includes all mandatory features. You can refer to RegulationCompliantCar as a base class. Then each maker can extend this class based on their needs and the result will be compliant with the regulations. For starters, let’s assume you have two famous makers: Mercedes and Honda.
You can create two classes, MercedesCar and HondaCar, both extending RegulationCompliantCar. We’ll call these derived classes. So currently, both Mercedes and Honda have a different car, equipped with the same (mandatory) features. From this point onwards, each maker can add additional features as it sees fit best.
For example, MercedesCar could add features like distraction recognition and lane keeping assist. HondaCar could add other features such as Event data recorder in case of accident and breath analyzers to prevent drunk driving.
There you go, you have successfully applied inheritance => you have a base class: RegulationCompliantCar and two derived classes: MercedesCar and HondaCar. You managed to “copy” the behavior and data of RegulationCompliantCar (without actually copy-pasting the code) while extending it by adding new features.
Please note that there are other synonyms for these two terms:
a base class is also known as super class or parent class
a derived class is also known as subclass or child class
Don’t get confused about the terminology, it’s basically the same concept.
At some point, these regulations will be updated. Let’s say that all cars will need to also have anti-speeding technology. When that happens, you’ll be covered => because you used inheritance, you will need to extend the features in the base class (RegulationCompliantCar) and the change will propagate in all other derived classes (MercedesCar, HondaCar).
Now, imagine that instead of 2 maker cars you had 100. With inheritance, accommodating the above change will be simple, fast and safe.
If you didn’t know about inheritance, you would most likely start creating a single maker car – e.g. MercedesCar. Then copy-paste the code for the mandatory features to HondaCar. Then do the same thing for the rest of 98 cases.
In this case, when the regulations will be updated, you would need to change 100 classes. How screwed are you now? This of course is not simple, takes (way) longer and the risk of breaking something increases.
Bottom line: inheritance helps in these cases!
The WHY
So by now, I assume you see the power of inheritance. When applied correctly, it saves you lots of headaches and the changes you need to make will be done fast, in a single place with low risk of breaking any other functionality. It helps keep your sanity healthy, it makes your code maintainable.
However, when applied incorrectly, it gives you much more headaches.
Inheritance is tricky and you need to know when to apply it and when NOT to apply it as it’s very easy to make mistakes here. To ensure you can’t go wrong, there is a trick you can use to determine the relationship between a base class and a derived class.
If the two classes are in a <is a> relationship => MercedesCar IS A RegulationCompliantCar, then the inheritance is applied correctly.
The other possible option is the <has a> relationship => MercedesCar HAS AN Engine (Engine is just another class), then we are not talking about inheritance, we are dealing with composition. In contrast, MercedesCar HAS A RegulationCompliantCar doesn’t make much sense. Composition allows you to model objects that are made up of other objects, but more on composition in a future article.
Conclusion
The thing to remember is that if you want to apply inheritance, make sure you check the “compatibility” of the classes by using the <is a> relationship. If it makes sense (such as MercedesCar IS A RegulationCompliantCar), go ahead, use inheritance.
In case the <has a> relationship fits better (MercedesCar HAS AN Engine), then usually, it would be a bad idea to add inheritance as it would be incorrectly applied, and headaches will follow (also depends on how you name your classes).
Inheritance is tricky and one can easily make mistakes here.
Keep in mind that inheritance brings complexity to a project and complexity kills projects. If you decide to use inheritance, make sure it is properly applied and keep it as simple as possible. Avoid complicating things without a reason as this will most likely kill your project. Use a KISS approach.
Note: you could have used a multi-level inheritance in some cases: RegulationCompliantCar -> MercedesCar -> HondaCar. Even though such an approach might make sense depending on the context, it will add even more complexity to your code. I wanted to keep things simple and used single-level inheritance for this example, but there are cases where a multi-level inheritance might make more sense, in which case go for it.
Just be careful to not go too far as these multi-level dependencies can turn into nightmares fast.
Still having questions? Contact me via Facebook or drop me a line, I’ll follow up on it, I promise.
Commentaires