Composition vs Inheritance

Composition vs Inheritance is one of the most important design decisions in object-oriented programming. Let’s dive deep with code, principles, and practical examples.

🧠 What Are They?

ConceptDescription
InheritanceOne class inherits fields and methods from another (a “is-a” relationship).
CompositionOne class contains an instance of another class (a “has-a” relationship).

They are both ways to reuse and organize code, but they serve different design goals.


🧬 Inheritance β€” β€œis-a” Relationship

βœ… When to Use:

  • When two classes share a hierarchical relationship.
  • When you want to extend or specialize the behavior of a base class.

πŸ“¦ Example:

class Engine {
    void start() {
        System.out.println("Engine started");
    }
}

class Car extends Engine {
    void drive() {
        System.out.println("Car is driving");
    }
}

πŸ”Ž What’s happening?

  • Car inherits start() from Engine.
  • But this creates a tight coupling β€” Car is forced to be an Engine, which might not be accurate.

πŸ”§ Composition β€” β€œhas-a” Relationship

βœ… When to Use:

  • When two classes are not logically in a strict hierarchy.
  • When you want flexibility, loose coupling, and better testability.

πŸ“¦ Example:

class Engine {
    void start() {
        System.out.println("Engine started");
    }
}

class Car {
    private Engine engine = new Engine(); // Composition

    void startCar() {
        engine.start(); // Delegation
        System.out.println("Car is ready to drive");
    }
}

πŸ”Ž What’s happening?

  • Car has an Engine, but is not an engine.
  • This is cleaner and more realistic β€” behavior is delegated rather than inherited.

βš–οΈ Composition vs Inheritance: Design Comparison

AspectInheritanceComposition
Relationshipis-ahas-a
CouplingTightLoose
FlexibilityLowHigh
ReusabilityIn base-child chainsThrough delegation
TestingHarderEasier (swap components)
Real-world modelingOften forcedMore accurate

πŸ’‘ Design Principle

Favor composition over inheritance β€” (Effective Java, Item 18)

Inheritance is powerful but often overused. Composition leads to better encapsulation, flexibility, and maintainability.


πŸ” Hybrid Example

You can even mix both:

class Engine {
    void start() {
        System.out.println("Engine starts...");
    }
}

class Vehicle {
    Engine engine = new Engine(); // Composition

    void startVehicle() {
        engine.start();
    }
}

class Car extends Vehicle {
    void drive() {
        System.out.println("Car is driving...");
    }
}

Here, Car inherits from Vehicle, and Vehicle uses composition for Engine.


🏠 Homework for Students

πŸ“Œ Task:

  1. Inheritance:

    • Create a class Bird with a method fly().
    • Create a subclass Sparrow that adds method sing().
  2. Composition:

    • Create a class Speaker with a method playMusic().
    • Create a class Smartphone that has a Speaker object and a method playSong() which delegates to playMusic().
  3. Questions to Answer (in comments or writeup):

    • Which approach is more flexible and why?
    • What happens if you need to change Speaker logic in the future?
    • Can you reuse Speaker in another class without changing it?

Would you like to move next into Static Keyword, Final Keyword, or Association vs Aggregation vs Composition for a deeper dive into OOP relationships?