Favoring Composition Over Inheritance

Sheldon Cohen
3 min readMay 19, 2023
Favoring Composition Over Inheritance

“Favor composition over inheritance” is a design principle that suggests it’s better to compose objects to achieve polymorphic behavior and code reuse rather than inheriting from a base class.

In object-oriented programming (OOP), we find two fundamental relationships that describe how objects relate and interact with each other: ‘IS-A’ and ‘HAS-A’. These relationships form the bedrock of inheritance and composition respectively. Let’s first elucidate these terms.

IS-A vs. HAS-A

In OOP, ‘IS-A’ is a relationship where one object is a subtype of another. A Car is a Vehicle, a Dog is an Animal; this relationship is manifested through inheritance. The ‘HAS-A’ relationship is where one object contains or uses another object. A Car has an Engine, a Dog has a Tail; this relationship is realized through composition.

Inheritance allows you to define a new class based on an existing one, thereby promoting reusability and code organization. On the other hand, composition is a way to combine simple objects or data types into more complex ones.

Composition Over Inheritance

Despite the benefits of inheritance, it has its downsides. A major one is the tight coupling it creates, making a system rigid and harder to modify. Also, it can lead to a confusing hierarchy when overused. This is where the concept of favoring composition over inheritance comes into play.

With composition, you build complex objects by composing them of simple ones. Changing the behavior of a system involves changing the components, which are easier to manage than tangled inheritance hierarchies. Here’s an example in C# to illustrate this.


interface IEngine
{
void Start();
}

class CombustionEngine : IEngine
{
void IEngine.Start()
{
Console.WriteLine("Starting the combustion engine.");
}
}

class ElectricEngine : IEngine
{
void IEngine.Start()
{
Console.WriteLine("Starting the electric engine.");
}
}

class Car
{
private IEngine _engine;

public Car(IEngine engine)
{
_engine = engine;
}

public void Start()
{
_engine.Start();
}
}

Here, the Car class doesn’t inherit from the Engine class. Instead, it uses composition, making it flexible to accommodate any type of engine. You can easily change the engine type by changing the object the car is composed of.

When is inheritance is better suited?

A rule of thumb for when to use composition over inheritance is when you want to model a HAS-A relationship, or when you find yourself wanting to inherit from multiple classes, which is not supported in many languages such as C#.

Inheritance is often better suited when there is a clear IS-A relationship, and the subclass really is a type of the superclass. If you’re dealing with an IS-A relationship that doesn’t require much flexibility or change, inheritance might still be the way to go.

For example, if you have a base class Animal, and subclasses like Dog and Cat that share common behavior with additional specific behaviors, inheritance makes sense.


abstract class Animal
{
public virtual void Eat()
{
Console.WriteLine("Eating…");
}
}

class Dog : Animal
{
public override void Eat()
{
base.Eat();
Console.WriteLine("Dog is eating…");
}
}

In this example, the Dog IS-A Animal, hence it makes sense to use inheritance.

Unit Test Using Composition

Unit testing is another area where composition can be favored over inheritance. If we continue with the Car example, let’s see how we can use composition for more modular, maintainable tests.


[TestFixture]
public class CarTests
{
private Mock<IEngine> _mockEngine;
private Car _car;

[SetUp]
public void Setup()
{
_mockEngine = new Mock<IEngine>();
_car = new Car(_mockEngine.Object);
}

[Test]
public void Start_Called_CallsEngineStart()
{
// Act
_car.Start();
// Assert
_mockEngine.Verify(e => e.Start());
}
}

Here, we use a mock Engine to test the Car class independently, illustrating the advantages of composition for creating isolated, easy-to-maintain tests. By using composition, we avoid issues related to shared state between tests that can occur with test classes that inherit from each other.

Composition is a powerful tool that can be used to achieve code reuse and flexibility in object-oriented programming. It is important to understand the difference between composition and inheritance and to use composition as well as where and when to use it.

--

--

Sheldon Cohen

Technology professional with 15+ years of software development