I think this is the first time I am writing something technical on this blog. But I could not resist throwing some thoughts into the fray on the age old, well-known, generally accepted comparison between inheritance and composition.
In my opinion, everything in any engineering discipline revolves around cost.
What are the costs?
- Maintenance or Operational
Usually, maintenance costs tend to outweigh initial development costs. You need to make sure that your system is open to maintenance as much as possible so that any maintenance operation that is undertaken is as cheap as possible. Here again, the primary question that needs to be answered is how maintainable should my system be? You can spend a lot of time opening up your system for a particular maintenance extension point with the actual scenario never happening. A good engineer, therefore, decides what to spend more time on during development and what to reserve for later.
Software is no different from other engineering disciplines. That’s why it’s called software engineering. Duh.. The one advantage that software engineers have is that software systems are much more malleable and cheaper to change than their hardware counterparts. But that doesn’t mean we can rest easy.
The easiest way to make any system easily maintainable is to have independent parts that can be plugged in and taken out of the system easily. (What software engineering textbooks call coupling, rather decoupling).
Inheritance vs. Composition
Finally, we get to what I actually wanted to say 🙂
Inheritance is nothing but one class inheriting the behavior of another. (I think they ripped this idea off from Darwin) It’s cool in a way that your class will have the same behavior (i.e, the same external points of interaction) as some class that some other guy wrote. The coolest part, however, is that an instance/object of your class can be used in any place as the class that you inherited from. Just as natural inheritance has a few mutations associated with it, you can mutate existing methods in terms of their behavior by overriding them in the derived class and providing your own behavior.
The only caveat here is that your class is tightly coupled to the class you are inheriting from. In other words, any changes that the guy who wrote the base class makes to the external points of interaction (your public/protected methods) are going to have an impact on your class. This may be desirable in some cases, in some cases not. So, if any clients use your class directly they are now dependent on the base class that you inherited from as well. In general, you always want to refer to the base class as much as possible so that you can plug in whatever overriden behavior whenever you want. A simple example is that a rectangle is a shape, a circle is a shape, a triangle is a shape, etc. If a graphics package wanted to draw a shape, it just needs to take a reference of Shape and call its draw() method. You can pass along your Rectangle, Circle or Triangle and define how you want it to be drawn by overriding the draw() method. Beautiful, isn’t it? Now, if you wanted to create a Square class, would you inherit from Shape or Rectangle? It would make perfect sense to inherit from Rectangle because a square is a rectangle. (There is a condition that needs to be enforced that the square’s length and width are equal. You might need to add some more checks in your Square class to ensure that this is always true)
The classic mantra that gurujis advocate is that Inheritance is a “is-a” relationship. This is a pretty cool way to capture this idea.
Coming to composition now, the classic mantra here is that Composition is a “has-a” relationship. I am perfectly okay with this. Composition is containing an instance of another class instead of inheriting it.Take the below shape:
It is pretty straightforward that this shape is NOT a rectangle. However, it is made up of rectangles and you have an obvious composition relation here. It’s as simple as that. No hidden gotchas!!
Sadly, this obviousness is not there in a lot of real-life scenarios and people tend to get confused. Another simple mantra that I use is Composition is a “uses-a” relationship. For many, this doesn’t make much difference in the way they look at composition. It’s the same thing wrapped in a different cover, but this view tends to give better clarity in some cases.
Now, why is composition better than inheritance?
If you compose, an instance of your class cannot be used in place of an instance of the class that you are composed of, unlike inheritance, where an instance of your class can be used in place of an instance of the class that you inherit from. This might look like a hard thing to live with, but makes perfect sense if the domain relationship that you are capturing is actually composition 🙂 Another detail in terms of coupling is that your clients are dependent on the external points of interaction of your class only, and not on those of the class that you are composed of.
- Inheritance is a “is-a” relationship
- Composition is a “[has-a][uses-a]” relationship.
I haven’t been able to capture my thoughts exactly. I’ll try to come back later and make this better.