Tutorials Home   >   Object-Oriented Programming (OOP)   >   Composition vs Inheritance

Composition vs Inheritance

In object-oriented programming (OOP), we use relationships between classes to build powerful and reusable software. Two of the most important relationships are:

  • Inheritance – an “is-a” relationship

  • Composition – a “has-a” relationship

Understanding the difference between composition and inheritance is very important for writing clean, flexible, and maintainable code.


2. What Is Inheritance?

Definition

Inheritance is a mechanism where:

  • One class (child or subclass) inherits properties and methods from another class (parent or superclass)

The child class automatically gets the behavior of the parent class and can:

  • Use it

  • Extend it

  • Override it

Inheritance represents an “is-a” relationship.

Example of Inheritance

class Animal {
void eat() {
System.out.println("Animal eats");
}
}
class Dog extends Animal {
void bark() {
System.out.println(“Dog barks”);
}
}

Here:

  • Dog is an Animal

  • Dog inherits the eat() method


3. Advantages of Inheritance

Inheritance provides:

  1. Code reusability

  2. Method overriding

  3. Polymorphism

  4. Hierarchical classification

  5. Easy extension of functionality

Inheritance is useful when classes are closely related.


4. Limitations of Inheritance

Although inheritance is powerful, it has some drawbacks:

  1. Tight coupling

    • Child class strongly depends on parent class

  2. Fragile base class problem

    • Changes in parent class may break child classes

  3. Not flexible

    • Behavior is fixed at compile time

  4. Incorrect modeling

    • Sometimes “is-a” relationship is misused

  5. Single inheritance limitation (in Java)

Because of these issues, inheritance should be used carefully.


5. What Is Composition?

Definition

Composition is a design technique where:

  • One class contains an object of another class

  • Functionality is achieved by delegation

Composition represents a “has-a” relationship.

Example of Composition

class Engine {
void start() {
System.out.println("Engine starts");
}
}
class Car {
private Engine engine = new Engine();void drive() {
engine.start();
System.out.println(“Car is moving”);
}
}

Here:

  • Car has an Engine

  • Car uses Engine functionality without inheriting from it


6. Advantages of Composition

Composition offers several benefits:

  1. Loose coupling

  2. Greater flexibility

  3. Better code reuse

  4. Easy to change behavior

  5. Safer design

  6. Supports runtime changes

Because of these advantages, many experts recommend:

“Favor composition over inheritance.”


7. Inheritance vs Composition (Key Differences)

Inheritance Composition
“Is-a” relationship “Has-a” relationship
Uses extends keyword Uses object reference
Strong coupling Loose coupling
Behavior fixed at compile time Behavior can change at runtime
Less flexible More flexible
Parent class controls behavior Class controls behavior

8. When to Use Inheritance

Use inheritance when:

  1. There is a true “is-a” relationship

  2. Classes are closely related

  3. Behavior should be shared and extended

  4. Polymorphism is required

  5. The design is stable

Example (Correct Use)

class Shape {
void draw() {
System.out.println("Drawing shape");
}
}
class Circle extends Shape {
void draw() {
System.out.println(“Drawing circle”);
}
}

Here:

  • Circle is clearly a Shape


9. When to Use Composition

Use composition when:

  1. There is a “has-a” relationship

  2. Behavior may change in the future

  3. Classes are not closely related

  4. You want loose coupling

  5. Flexibility is important

Example

class MusicSystem {
void playMusic() {
System.out.println("Playing music");
}
}
class Car {
private MusicSystem music = new MusicSystem();void start() {
music.playMusic();
System.out.println(“Car started”);
}
}

Here:

  • Car has a MusicSystem

  • The music system can be replaced without changing the car class much


10. Real-Life Example

Inheritance Example (Not Ideal)

class Bird {
void fly() {
System.out.println("Bird flies");
}
}
class Penguin extends Bird {
}

Problem:

  • Penguins cannot fly

  • Inheritance is misused

Composition Example (Better Design)

class FlyBehavior {
void fly() {
System.out.println("Flying");
}
}
class Bird {
FlyBehavior flyBehavior;
}

Now:

  • Flying behavior can be added or removed

  • Design is more flexible


11. Polymorphism in Inheritance vs Composition

Inheritance Polymorphism

  • Achieved through method overriding

  • Parent reference points to child object

Composition Polymorphism

  • Achieved through interfaces

  • Behavior is delegated to objects

Composition often leads to cleaner polymorphic designs.


12. Composition with Interfaces

Composition works very well with interfaces.

Example

interface Engine {
void start();
}
class PetrolEngine implements Engine {
public void start() {
System.out.println(“Petrol engine starts”);
}
}class DieselEngine implements Engine {
public void start() {
System.out.println(“Diesel engine starts”);
}
}

class Car {
private Engine engine;

Car(Engine engine) {
this.engine = engine;
}

void drive() {
engine.start();
System.out.println(“Car is moving”);
}
}

This allows:

  • Changing engine type at runtime

  • Highly flexible design


13. Common Mistakes by Learners

  1. Using inheritance everywhere

  2. Confusing “is-a” with “has-a”

  3. Creating deep inheritance hierarchies

  4. Ignoring composition

  5. Poor real-world modeling


14. Advantages of Choosing the Right Approach

Choosing correctly between inheritance and composition:

  1. Improves code quality

  2. Makes applications flexible

  3. Reduces bugs

  4. Improves maintainability

  5. Supports future changes


15. Exam-Oriented Summary

Inheritance

  • Reuses code using extends

  • Represents “is-a” relationship

  • Strong coupling

  • Less flexible

Composition

  • Reuses code using objects

  • Represents “has-a” relationship

  • Loose coupling

  • More flexible


16. Final Summary

Both inheritance and composition are powerful tools in object-oriented programming. However, they should be used wisely.

Key Takeaways

  • Use inheritance for true “is-a” relationships

  • Use composition for “has-a” relationships

  • Favor composition for flexibility

  • Combine composition with interfaces for best design

Understanding Composition vs Inheritance is essential for designing robust, scalable, and real-world software systems.