Favor Composition Over Inheritance part 2

Yesterday I wrote part one of my two part series on why we should favor the technique of composition over inheritance. I began by looking at how a purely inheritance-based model quickly becomes unworkable as the properties and methods of base classes often lead to an inflexible design. Today, by contrast, I will look at solving the same problem by the use of composition. Specifically, we will look at how using interfaces for composition in C# allows for a highly flexible design.

The problem posed yesterday was to model the behavior of a car when a driver applies changes to it. I want to be able to track the angle of the wheels and the speed at which the wheels have been turned by the engine. The first car to model is the Toyota Corolla.

Yesterday, the first class that was designed was the BaseCar class, which contained a number of abstract methods which defined our behavior. It also contained our wheels. Today, instead, I am going to look at the behaviors of the car. It seems to me that there are two separate behaviors which are independent of each other. There is steering and there is driving (or accelerating). These behaviors will form the basis for our interface design. A car also has a manufacturer, so we will create an interface for that too.

interface IDriving
{
  void Accelerate(double kph);
}

interface ISteering
{
  void TurnLeft(double degrees);
  void TurnRight(double degrees);
}

interface IManufacturer
{
  string Name { get; }
}


There are a couple of ways that we could look at designing the car interface. We could say that an ICar inherits from both ISteering and IDriving, but instead I think we should say that an ICar has both an ISteering and IDriving. This seems to make the most sense.

interface ICar
{
  IWheel FrontLeft { get; }
  IWheel FrontRight { get; }
  IWheel RearLeft { get; }
  IWheel RearRight { get; }

  ISteering Steering { get; }
  IDriving Driving { get; }
  IManufacturer Manufacturer { get; }
}


Already we can see that simply by thinking about the components and how they logically relate to each other, we have created a different design from before. The interfaces help us think more abstractly than base classes would otherwise had. Now that we have designed our interfaces (and the astute reader might have noticed that the Wheel class has now become an IWheel interface too, though defining either is beyond the scope of these articles) we can get started on defining the functionality of our classes.

First we will create a TwoWheelDrive class which implements the IDriving interface.

class TwoWheelDrive : IDriving
{
  private readonly IWheel left;
  private readonly IWheel right;

  public TwoWheelDrive(IWheel left, IWheel right)
  {
    this.left = left;
    this.right = right;
  }

  public void Accelerate(double kph)
  {
    this.left.RotationSpeed += kph;
    this.right.RotationSpeed += kph;
  }
}


Immediately it can be seen that this class can be used for both types of two wheel drive car – front or rear. All we will have to do is pass either the front or rear wheels to it. Next up we’ll implement the two wheel steering functionality in much the same way. Note that in this case, the steering class has to be a “front” steering class or a “rear” steering class, as each type of steering requires the wheels to turn in opposite directions to achieve the same outcome for the driver.

class FrontSteering : ISteering
{
  private readonly IWheel frontLeft;
  private readonly IWheel frontRight;

  public FrontSteering(IWheel frontLeft, IWheel frontRight)
  {
    this.frontLeft = frontLeft;
    this.frontRight = frontRight;
  }

  public void TurnLeft(double degrees)
  {
    this.frontLeft.Angle -= degrees;
    this.frontRight.Angle -= degrees;
  }

  public void TurnRight(double degrees)
  {
    this.frontLeft.Angle += degrees;
    this.frontRight.Angle += degrees;
  }
}


And next, my Toyota manufacturer class. I’ve implemented it as a singleton because that will be sufficient for this problem.

class Toyota : IManufacturer
{
  private static IManufacturer instance;

  private Toyota() { }

  public string Name { get { return "Toyota"; } }

  public static IManufacturer GetInstance()
  {
    return instance ?? (instance = new Toyota());
  }
}


Finally, I can create my ToyotaCorolla class.

class ToyotaCorolla : ICar
{
  public ToyotaCorolla()
  {
    this.FrontLeft = new Wheel();
    this.FrontRight = new Wheel();
    this.RearLeft = new Wheel();
    this.RearRight = new Wheel(0, 0);
    this.Steering = new FrontSteering(this.FrontLeft, this.FrontRight);
    this.Driving = new TwoWheelDrive(this.FrontLeft, this.FrontRight);
    this.Manufacturer = Toyota.GetInstance();
  }

  public IWheel FrontLeft { get; private set; }
  public IWheel FrontRight { get; private set; }
  public IWheel RearLeft { get; private set; }
  public IWheel RearRight { get; private set; }
  
  public ISteering Steering { get; private set; }
  public IDriving Driving { get; private set; }
  public IManufacturer Manufacturer { get; private set; }
}


Now when the customer comes along and asks for the rear wheel drive sports edition, I can create the following class for them.

class ToyotaCorollaSports : ICar
{
  public ToyotaCorollaSports()
  {
    this.FrontLeft = new Wheel();
    this.FrontRight = new Wheel();
    this.RearLeft = new Wheel();
    this.RearRight = new Wheel(0, 0);
    this.Steering = new FrontSteering(this.FrontLeft, this.FrontRight);
    this.Driving = new TwoWheelDrive(this.RearLeft, this.RearRight);
    this.Manufacturer = Toyota.GetInstance();
  }

  public IWheel FrontLeft { get; private set; }
  public IWheel FrontRight { get; private set; }
  public IWheel RearLeft { get; private set; }
  public IWheel RearRight { get; private set; }
  
  public ISteering Steering { get; private set; }
  public IDriving Driving { get; private set; }
  public IManufacturer Manufacturer { get; private set; }
}


In fact, it is at this point that you can quite easily see that the only difference between ToyotaCorollas lies in the parameters that are passed into the driving constructor. A pattern is emerging. We now have the ability to do away entirely with our ToyotaCorolla class. The only difference is in our constructor parameters. What I can do instead is refactor my code and use constructor parameters to define our classes.

class Car : ICar
{
  public Car(IWheel frontLeft, IWheel frontRight, IWheel rearLeft,
            IWheel rearRight, ISteering steering, IDriving driving, 
            IManufacturer manufacturer, string carName)
  {
    this.FrontLeft = frontLeft;
    this.FrontRight = frontRight;
    this.RearLeft = rearLeft;
    this.RearRight = rearRight;
    this.Steering = steering;
    this.Driving = driving;
    this.Manufacturer = manufacturer;
    this.Name = carName;
  }

  public IWheel FrontLeft { get; private set; }
  public IWheel FrontRight { get; private set; }
  public IWheel RearLeft { get; private set; }
  public IWheel RearRight { get; private set; }
  
  public ISteering Steering { get; private set; }
  public IDriving Driving { get; private set; }
  public IManufacturer Manufacturer { get; private set; }
  public string Name { get; private set; }
}

static class CarFactory
{
  public static ICar ToyotaCorolla()
  {
    IWheel frontLeft = new Wheel();
    IWheel frontRight = new Wheel();
    return new Car(frontLeft, frontRight, new Wheel(), new Wheel(), 
      new FrontSteering(frontLeft, frontRight), 
      new TwoWheelDrive(frontLeft, frontRight), Toyota.GetInstance(), 
      "Corolla");
  }
  public static ICar ToyotaCorollaSports()
  {
    IWheel frontLeft = new Wheel();
    IWheel frontRight = new Wheel();
    IWheel rearLeft = new Wheel();
    IWheel rearRight = new Wheel();
    return new Car(frontLeft, frontRight, rearLeft, rearRight, 
      new FrontSteering(frontLeft, frontRight), 
      new TwoWheelDrive(rearLeft, rearRight), Toyota.GetInstance(), 
      "Corolla Sports");
  }
}


So as you can see, by using composition we have created a much more flexible design. We can reuse the bits that make sense to be reused and ignore the bits that don’t. The interfaces have helped us think abstractly and separated out how the objects relate to each other from how the objects work. We can use a car without knowing how the steering is implemented or whether it is a front, rear or four wheel drive. We no longer have a complicated object heirarchy and adding new car designs takes little effort. When it comes time to design a car with four wheel drive, all we need to do is create a four wheel drive class and a factory method.

Far too many professional developers think in an “is-a” mindset when they want to reuse code. I hope that I have sufficiently demonstrated that composition helps us reuse code far more efficiently and with a lot less complexity than using inheritance. As always, leave a comment, I would love to hear your feedback!

I am taking two weeks holiday, after which I will be (hopefully) blogging on a regular basis.

Advertisements

13 thoughts on “Favor Composition Over Inheritance part 2

  1. Great article! It clarified me a lot.
    However I can’t not see how much inheritance-oriented are OOP languages and, while still easy to implement, composition design feels not as natural as his buddy.
    Do you think there is a design problem in OOP languages themselves?

    • That’s a great question Matteo. If I were to go back in time and change the C# spec at version 1, I probably would change it so that classes were sealed by default. This would probably help, and certainly would make developers think before using inheritance.

      At a more fundamental level, I think that if composition mechanisms were more convenient, we would (as developers) use it more often. An example might be:

      If we are composing a class using Class A : ISomeInterface { public PropertyA {get; set;} public PropertyB { get;set; } Maybe we could have syntactic sugar like the following:

      ISomeInterface
      {
      PropertyB { get; set; }
      }

      public class B : ISomeInterface
      {
      private readonly ClassA classA = new ClassA();
      classA.PropertyA.get.Public();
      classA.PropertyA.set.Private();
      classA.PropertyB.get.Public();
      classA.PropertyB.set.ExposeExplicit(ISomeInterface.PropertyB.set);
      }

      The idea being that B would have PropertyA get and set implemented by classA, PropertyB get implemented by classA and the explict interface PropertyB setter implemented by classA.

      Perhaps this isn’t a good idea for some other reason I haven’t thought of, but I do agree with your fundamental point that inheritance is much easier than composition, which is due to the language mechanisms.

  2. Thanks for your great article. I have a thought to share: I think inheriting behavior is not a good idea but inheriting properties can be useful. For example you could have Manufacturer in BaseCar abstract class and use it in subclasses.

  3. Great article Stephen, this is really helping me get my head around proper OOP. I’m finding the step from having abstract bass classes to composing many (if required) interfaces tougher on the brain. I’ve been a hobby type programmer for some years but very procedural, the proper use of objects in design patterns is an exciting new world for me. Cheers!

  4. Great article! Really enjoyed reading, and from now on I’ll look at my code with another eyes. Thanks for sharing such good examples!

  5. What about a 3 wheel car, an autocycle. Or a dually truck. I don’t think anyone needs to know how many wheels a car has to be able to accelerate it and steer it. Only the implementation is concerned with the collection of wheels, or it could be a hovercraft or amphibious.

  6. Is there any reason the static factory functions like ToyotaCorolla() return an ICar instead of a Car? Since you are creating a new Car right in the function, so you know that the return type is not just ICar, but Car, wouldn’t it make sense to give the stricter guarantee?

    • Great question.

      The main reason for returning an ICar is that it gives us the most flexibility going forward. Imagine if we had created the factory method earlier when we had the ToyotaCorolla concrete class. When we wanted to refactor and get rid of the ToyotaCorolla class we would then have had to go and update everywhere that our code was expecting a ToyotaCorolla to instead expect a Car. We would have to ensure that nothing in our code was depending on anything in the specific ToyotaCorolla class implementation. Furthermore, any code that wants the Car class will not be able to accept a Bus, which may validly implement ICar. By forcing users to accept an ICar instead of a Car, you are forcing them to write more generic code which makes the application more robust. Also, if ToyotaCorolla or Car is a class that is expensive to create or methods on it are expensive to run, it’s much harder to create tests around because I can’t mock the interface in my unit tests.

      You see if I am passing around an ICar, I can mock an ICar and I can test using the assumptions that the interface provides, rather than tying myself to the (potentially buggy or limited) explicit concrete implementation provided by Car. I can test new code without being dependent on the specifics of the Car class.

      Technically speaking there is nothing wrong with returning a Car, after all, it implements ICar. But why should the calling code know that? Why should the calling code ever care? It’s safer just to return an ICar and then force the user to cast (knowing that casts are dangerous) if they want to do something with the implementation. Then tomorrow when we decide that we have to refactor again we don’t have to worry about anyone who called our ToyotaCorolla factory method because they’re still getting an ICar.

      Another way to think of it is to forget about the code in the method and think about the method signature. We’re asking for a ToyotaCorolla and getting an instance of an ICar. We don’t actually care what implementation of ICar we’re getting, we only care that it in some way represents a ToyotaCorolla. There should never really be a reason why a consumer would want the Car class explicitly and if they absolutely must have it they can cast it. With this solution our Car class and ICar interface can be in different dlls and our calling class won’t have to take a dependency on the dll that Car is in.

      Our SOLID principles tell us that we should depend on abstractions over concretions. Returning an abstraction rather than a concretion is a good habit to get into. It helps a lot. I only wish that some of the System classes (List I’m looking at you) would expose more of their methods on interfaces rather than only on their concrete types.

      That was overly long and I’m sorry for that. I really liked the question though as it made me think over my own code practices and why I developed them.

      TL;DR – In this example it’s not too important but it’s a good habit to get into because it makes future refactoring easier and decreases concrete coupling between our components.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s