Composition vs Inheritance
TL;DR
- Inheritance models an IS-A relationship (e.g., A
CarIS-AVehicle). - Composition models a HAS-A relationship (e.g., A
CarHAS-AEngine). - Design Principle: “Favor Composition over Inheritance”. It leads to more flexible, modular, and testable code.
Concept
Inheritance tightly couples the child class to the parent class. If the parent changes, it can easily break the child (the fragile base class problem).
Composition, on the other hand, means injecting an object into another object to use its functionality, rather than inheriting from it. This allows you to swap out behaviors at runtime.
When to use which?
Use Inheritance only when a subclass truly is a specific type of the superclass and you want to utilize polymorphism. If you just want to reuse code, use Composition.
Examples
// --- THE WRONG WAY: INHERITANCE ---
class Engine {
public void start() { System.out.println("Engine starting"); }
}
// Does a Car "IS-A" Engine? No! This is bad design.
class CarBad extends Engine { }
// --- THE RIGHT WAY: COMPOSITION ---
class CarGood {
private final Engine engine; // Car HAS-A Engine
// Dependency Injection
public CarGood(Engine engine) {
this.engine = engine;
}
public void drive() {
engine.start(); // Delegating the work
System.out.println("Car is moving");
}
}
Interview Questions
Q: Why is the phrase “Favor Composition over Inheritance” so famous?
A: Because deep inheritance trees become extremely rigid. If you want to change a method in a deeply nested parent class, it ripples down and might break dozens of subclasses. Composition provides loose coupling. You can easily swap an ElectricEngine for a GasEngine in a Car via composition (as long as they share an interface), but you cannot change what class Car extends at runtime.
Q: Can you achieve Polymorphism with Composition?
A: Yes, by composing interfaces. Instead of private Engine engine, you can have private IEngine engine. You can then inject any class that implements IEngine into your object, achieving polymorphic behavior without traditional class inheritance.