Choosing composition over inheritance: yet another example!

Julien on May 30th 2008

A friend of mine recently asked me if I though that having an inheritance hierarchy with a depth of 10 classes was acceptable or not. I don't think it is. If you take a class at the bottom, any change to the 9 classes above can introduce a breaking change. It can quickly become a maintenance nightmare!

Most of the time, if you have that kind of hierarchy in your application, it means that you chose inheritance over composition. It's probably also a code-smell indicating that your class is doing too much. To avoid that, let me show you how it is possible to extend a class without using inheritance.

Let's assume that we start with the following code. I know it's very basic, however it's still enough for our demonstration.

We have a BaseTrip abstract class and we want to extend it by having 2 sub classes: CarTrip and PlaneTrip. In a real application, we would have some kind of algorithm to calculate or fetch the transportation time and it would probably be very different for each class. In this example, to simplify, we just return a hard coded value.
This code is not bad, however it's not perfect either. For instance, are we sure that calculating the transportation time between 2 city is the responsibility of the CarTrip and the PlaneTrip class? As a matter of fact, if we want to add a new MotocycleTrip class that would have different properties but the same algorithm than CarTrip to calculate the transportation time, we would need to extract a new abstract superclass that we would probably call RoadTrip... It doesn't look good...

Here is a refactored version of these class, using composition instead of inheritance:

In a few words, I've extracted the calculations in their own classes that implement an ITransportationMode interface. They are injected in the Trip class through the constructor (but we could also use a setter injection or a method injection).

This implementation improves the code in several way:

  • The calculation of the transportation time is done in a new class, it's not polluting our Trip class any more. It's a lot easier to add new algorithms, we just need to add a new implementation of ITransportationMode. It can evolves independently of the Trip class. It's called the separation of concern principle.
  • We can more easily configure our Trip class. Before, wa had to create a new instance of a TripBase sub class to change the way the calculation was done, now we can just change the instance of ITransportationMode while keeping the same Trip object.
  • We can have several subclasses of Trip using the same algorithm without introducing a new abstract class (such as RoadTrip). Therefore, composition helps us to keep our hierarchy of class flat.

kick it on DotNetKicks.com

Filed in General development | 17 responses so far

17 Responses to “Choosing composition over inheritance: yet another example!”

  1. Thomas Jensen Feb 6th 2009 at 11:30 pm 1

    Thanks…:)

  2. Nick Wiggill Feb 11th 2009 at 09:24 pm 2

    Excellent, thanks for a simple example Julien.

  3. Nick Wiggill Feb 14th 2009 at 03:31 pm 3

  4. brad Mar 11th 2009 at 02:25 pm 4

    how do you run this code?

    CarTransportationMode c = new CarTransportationMode();
    TimeSpan s = c.CalculateTransportationTimeBetween(“”, “”);

    I don’t see where the Trip class is used or the benefits of this?

  5. Julien Mar 12th 2009 at 09:20 am 5

    You would not use directry an instance of ITransportationMode, you would inject it in the Trip class like this :

    Trip tripToParis = new Trip(“barcelona”, “paris”, new PlaneTransportationMode());
    DateTime arrivalTime = tripToParis.CalculateEstimatedArrivalTime()

    The point is that this calculation can change and it should not be the responsability of the Trip class to perform it. Therefore, the best way to change the behavior of the trip class is not through inheritance but through composition.

    Now, keep in mind that this example is very basic and in a real application you would have real logic in CalculateTransportationTimeBetween() :)

  6. brad Mar 12th 2009 at 04:03 pm 6

    That’s what I thought, but the trip constructor that takes three arguments is assigned protected not public. If I change your example to public, it works fine. Was protected a mistype?

  7. Julien Mar 13th 2009 at 07:41 am 7

    It certainly was, my apologies !
    I’ll fix it right now !

  8. Anonymous Apr 1st 2009 at 11:04 pm 8

    Excellent

  9. Naveena Apr 1st 2009 at 11:04 pm 9

    Simple example.. thanks

  10. ?????? Oct 21st 2009 at 02:25 pm 10

    ???? ??? ?????

  11. Sunil Raskar Jun 17th 2011 at 09:14 am 11

    In trip or tripbase class, the _from or _to properties are declared as read only and it has been assigned a value in non default contractors. It should be not read only if values are require to assigned.

  12. Abhi Dec 13th 2011 at 12:04 pm 12

    Well done

  13. bibin Feb 6th 2012 at 07:10 am 13

    Well done explained with great ease..

  14. Sri Mar 8th 2012 at 06:35 am 14

    Nice explanation.

  15. vasu Aug 20th 2012 at 10:13 am 15

    great explanation…..tenx….

  16. amit Aug 20th 2012 at 10:14 am 16

    well done …dear…..

  17. Nitesh May 24th 2013 at 01:35 pm 17

    Nice article !!!

Trackback URI | Comments RSS

Leave a Reply