SJCNet

SJCNet is the home of architect/developer/techie, Simon Coope.

Composition and Inheritance

I've recently started working on a project that documents the various design patterns and approaches I use because although I've used design patterns extensively I can't always think up a great example when I want to share an idea with someone. To that end I've created a Github repo and will add to this in the future

I would also recommend the Head First Design Patterns book from O'Reilly. This is an amazing book for explaining design patterns in a fun and easy to understand way. The authors have also studied how best to present information in a way that makes it stick in the brain, which I've found really works! Also, the following coding examples are heavily based on an examples in this book, with only a few minor changes while creating a code example I put together after reading the book.

Overview

The first topic I'm going to tackle is composition and inheritance. I've read countless blogs and listened to many podcasts that mention this as the thing to do, but while I've understood the concept I've never put together an example of when/why you should use composition instead of inheritance. That's what I hope to achieve in the rest of this post.

Inheritance

In object-oriented programming, inheritance enables new objects to take on properties of existing objects. A class that is used as the basis for inheritance is called a superclass or base class. A class that inherits from a superclass is called a subclass or derived class. Adobe DevNet

This means we can have have a base class that has methods and properties that can be adopted by classes that inherit from the base class (derived classes). This is great for reuse if we have a method on the base class that we want all derived classes to use, we only need write it once and in one place.

Composition

in computer science, object composition is a way to combine simple objects or data types into more complex ones. Wikipedia.

Composition itself is quite easy to understand. It refers to what the parts or an object are, for example, a wall is composed of bricks. In terms of programming composition means we can compose an object of the desired behaviours to achieve reuse without necessarily needing to inherit.

Sample Application

The sample app developed in this example will follow the concept of a "Dog Simulator". The application will be able to register dogs and make them perform suitable actions (e.g. move, wag their tail, etc.).

I'm going to work through an example of creating a sample app and then updating the application when new requirements come in. The full code example can be found on my Github pages.

Inhertiance Example

So we've been asked to create a dog simulator application. We have been asked to implement two types of dog; Golden Retriever and Labrador. So using inheritance we may look to achieve a high level of reuse by implementing the following code.

public abstract class Dog
{
    protected Dog(string name)
    {
        this.Name = name;
    }

    public string Name { get; set; }

    public abstract void Display();

    public void Move()
    {
        Logger.Write("I am walking");
    }
}

public class GoldenRetrieverDog : Dog
{
    public GoldenRetrieverDog(string name) : base(name)
    {}

    public override void Display()
    {
        Logger.Write($"Hello, my name is {Name} and I am a Golden Retriever");
    }
}

public class LabradorDog : Dog
{
    public LabradorDog(string name) : base(name)
    {}

    public override void Display()
    {
        Logger.Write($"Hello, my name is {Name} and I am a Labrador");
    }
}

In the above code we can see that we have a Dog base class, from which we derive the GoldenRetrieverDog and LabradorDog classes. The Dog class has one abstract method Display which is overridden in the derived classes. Otherwise we can reuse the Dog.Move method and any other methods that are common between all derived classes.

So all in all this is a neat implementation, that's open for extension. But only if all derived classes have the same implementation details.

New Requirement

We've been approached and asked to implement functionality to make a dog bark. Our product owner has also mentioned that we're releasing some other kinds of dogs too, but we said the solution was open for extension, so that won't be a problem... right?

As we're using inheritance we can add the new Bark method onto the Dog class then it can be reused by all derived classes. Sounds simple, let's do that.

public abstract class Dog
{
    protected Dog(string name)
    {
        this.Name = name;
    }

    ... Removed other methods for brevity.

    public void Bark()
    {
        Logger.Write("I am woofing");
    }
}

This will work for the GoldenRetrieverDog and LabradorDog classes. But now the product owner mentions the other types of dog to add. These types are a wooden dog (a wooden statue of a dog that can't move or bark) and an electronic dog (a toy dog that can't move but can make a yipping sound). So you implement these types as follows (based on the existing subtypes derived from the Dog class).

public class WoodenDog : Dog
{
    public WoodenDog(string name) : base(name)
    {}

    public override void Display()
    {
        Logger.Write($"Hello, my name is {Name} and I am a Wooden Dog");
    }
}

public class ElectronicDog : Dog
{
    public ElectronicDog(string name) : base(name)
    {}

    public override void Display()
    {
        Logger.Write($"Hello, my name is {Name} and I am an Electronic Dog");
    }
}

So we run the code and get the following output.

Inheritance Example
----------------------------------------
23/04/2016 10:35: Hello, my name is Sammy and I am a Golden Retriever
23/04/2016 10:35: I am walking
23/04/2016 10:35: I am woofing
23/04/2016 10:35: Hello, my name is Ben and I am a Labrador
23/04/2016 10:35: I am walking
23/04/2016 10:35: I am woofing
23/04/2016 10:35: Hello, my name is Woody and I am a Wooden Dog
23/04/2016 10:35: I am walking
23/04/2016 10:35: I am woofing
23/04/2016 10:35: Hello, my name is Yippy and I am an Electronic Dog
23/04/2016 10:35: I am walking
23/04/2016 10:35: I am woofing

All is well! But is it? We haven't followed the requirements from the product owner. The wooden dog can't move or bark and the electronic dog can't move, but it's walking and woofing in the output. Hmmm...

So we start to think about other ways to implement. We could use interfaces (e.g. IMovable, IBarkable, etc.). But then we would have to implement the Bark and Move methods on each of the derived classes, meaning we get no resuse at all and would have to update each sub class each time there's a change in an implementation detail.

Now we need to step back and define the problem. We have sub classes that share some functionality but not all. But we also need to design the code in such a way that new types of dogs with new actions can be introduced that don't impact the existing dog types (i.e. making the types open for extension but closed for modification). But how do we do this? Enter composition...

Composition Example

Now to use composition instead of inheritance we need to move from thinking a GoldenRetriever IS A Dog (where the subtype can reuse the Move method from the super type) and instead move towards thinking a GoldenRetriever HAS A Move action. To achieve this we can use the Strategy Pattern.

Strategy Pattern

The strategy pattern defines a family of algorithms, encapsulates each algorithm and makes the algorithms interchangeable within that family. (Wikipedia)

This means that we can define a set of actions or behaviours for the dogs. Then encapsulate the implementation details within each of these actions/behaviours and make them interchangeable between the dogs (i.e. bark behaviours might be woof, yip or mute).

We'll start with the bark behaviours. First we implement an interface so that we can program to an interface rather than an implementation.

public interface IBarkBehaviour
{
    void Bark();
}

Now we implement the bark behaviours as follows.

public class WoofBehaviour : IBarkBehaviour
{
    public void Bark()
    {
        Logger.Write($"I am woofing");
    }
}

public class YipBehaviour : IBarkBehaviour
{
    public void Bark()
    {
        Logger.Write($"I am yipping");
    }
}

public class MuteBehaviour : IBarkBehaviour
{
    public void Bark()
    {
        Logger.Write($"I am mute");
    }
}

Next we extract the Bark implementation from the Dog class and replace it with a polymorphic reference to the behaviour.

public abstract class Dog
{
    protected Dog(string name)
    {
        this.Name = name;
    }

    // ... Other methods removed for brevity.

    protected IBarkBehaviour BarkBehaviour { get; set; }

    public void Bark()
    {
        this.BarkBehaviour.Bark();
    }
}

As we can see above the Dog base class doesn't know or care what the implementation of the Bark method is (the implementation is encapsulated and interchangeable). So now the only thing to do is to set-up each derived class to create it's own concrete implementation of the bark behaviour.

public class GoldenRetrieverDog : Dog
{
    public GoldenRetrieverDog(string name) : base(name)
    {
        base.BarkBehaviour = new WoofBehaviour();
        base.MoveBehaviour = new WalkBehaviour();
    }

    // ... Other methods removed for brevity.
}

public class WoodenDog : Dog
{
    public WoodenDog(string name) : base(name)
    {
        base.BarkBehaviour = new MuteBehaviour();
        base.MoveBehaviour = new NoWalkBehaviour();
    }

    // ... Other methods removed for brevity.
}

public class ElectronicDog : Dog
{
    public ElectronicDog(string name) : base(name)
    {
        base.BarkBehaviour = new YipBehaviour();
        base.MoveBehaviour = new NoWalkBehaviour();
    }

    // ... Other methods removed for brevity.
}

Finally, when we run the app we get the following output.

Composition Example
----------------------------------------
23/04/2016 10:36: Hello, my name is Sammy and I am a Golden Retriever
23/04/2016 10:36: I am woofing
23/04/2016 10:36: I am walking
23/04/2016 10:36: Hello, my name is Ben and I am a Labrador
23/04/2016 10:36: I am woofing
23/04/2016 10:36: I am walking
23/04/2016 10:36: Hello, my name is Woody and I am a Wooden Dog
23/04/2016 10:36: I am mute
23/04/2016 10:36: I am NOT walking
23/04/2016 10:36: Hello, my name is Yippy and I am an Electronic Dog
23/04/2016 10:36: I am yipping
23/04/2016 10:36: I am NOT walking

Excellent! Now we have the expected output and the application is also extendable because we can add new types of dogs, that require new behaviours without modifying the existing dog subtypes.

Wrap Up

This was a really quick and very simple example of where using strict inheritance can closely couple your derived classes to the base type. If we apply composition we can still use elements of inheritance that are useful but use composition for those areas of the design that we need the most amount of flexibility. We could of course remove the inheritance all together and just use composition, but that can also cause problems and I prefer to design picking parts of approaches I know will help me achieve my goals.

Though inheritance still has it's uses but I've found more and more that some of the more traditional OO concepts I was taught at uni are great as a foundation but moving forward we have to make our designs extendable by finding ways to ensure we adere to the [SOLID](https://en.wikipedia.org/wiki/SOLID_(object-oriented_design) principes of OO design. Because after all, the time spent writing the initial code is a fraction of the time spent reading, understanding, maintaining and updating the code once it's released.

Author image
About Simon Coope
Sydney, Australia Website
Experienced developer/consultant. Loves all things development, technology, gadgets, football and running.