When designing an OOP system, should you favor Composition (“has-a” relationship) or Inheritance (“is-a” relationship)?
You have to know that, in the scenario of modern object-oriented design principles, there is a strong preference for Composition over Inheritance as better design principle.
The key difference:
Inheritance (extends): Creates an “is-a” hierarchy, meaning the subclass is the superclass (e.g., Dog is a Animal). It is tightly coupled.
Composition (Instance Variable): Creates a “has-a” relationship, meaning the enclosing class has the other class as a component (e.g., Car has an Engine). It is loosely coupled and preferred for flexibility.
Why Favor Composition?
- Flexibility: With Composition (“has-a”), you can change the behavior of a class at runtime by simply swapping out one component object for another. Inheritance (“is-a”) is fixed at compile time.
 
- Avoids the “Fragile Base Class” Problem: A change to the base (parent) class in an inheritance hierarchy can unintentionally break the functionality of many derived (child) classes. Composition avoids this tight coupling.
 
- Encourages Better Design: Inheritance is best reserved for situations where a clear, verifiable “is-a” relationship exists (e.g., a 
Dogis-aMammal). Composition is better for situations where a class simply needs certain functionalities (e.g., aCarhas-aEngine). 
“Talk is cheap. Show me the code!”
Ok… Let’s see the code:
“is-a”: Inheritance (Tightly Coupled):
// "is-a": Inheritance (Tightly Coupled)
class Engine {
    // The base component (Superclass)
    public String start() {
        return "Engine is running.";
    }
}
class PetrolCar extends Engine {
    /* A PetrolCar IS-A Engine (poor design, but demonstrates 'is-a').
    It inherits the start() method from Engine. 
    */
    public String drive() {
        // Accesses the inherited method directly
        return start() + " The car is driving on petrol.";
    }
}
// Example Usage
public class InheritanceExample {
    public static void main(String[] args) {
        PetrolCar myCar = new PetrolCar();
        System.out.println("Inheritance Example: " + myCar.drive());
    }
}“has-a”: Composition (Loosely Coupled/Flexible)
// "has-a": Composition (Loosely Coupled/Flexible)
class Engine {
    // The component class
    public String start() {
        return "Engine is running.";
    }
}
class Car {
    // The Car HAS-A Engine object (Composition)
    private Engine engine;
    public Car() {
        // The Car creates (or is given) its Engine object
        this.engine = new Engine();
    }
    public String drive() {
        // The Car DELEGATES the task to its component object
        String engineStatus = this.engine.start();
        return engineStatus + " The car is driving using its composed engine.";
    }
    
    // Benefit of Composition: Easy to swap components (e.g., adding a setter)
    public void replaceEngine(Engine newEngine) {
        this.engine = newEngine;
    }
}
// Example Usage
public class CompositionExample {
    public static void main(String[] args) {
        Car myCar = new Car();
        System.out.println("Composition Example: " + myCar.drive());
    }
}So, should I never use inheritance? Or, when should I use inheritance?
You should use Inheritance when you have a very clear, verifiable “is-a” relationship between two classes. This is the only scenario where inheritance is the better choice, something like: Square is a Shape, Manager is an Employee or Sedan is a Car.
Leave a Reply