Bird
Raised Fist0
Interview Prepoop-design-patternsmediumAmazonGoogleMicrosoftFlipkartSwiggyRazorpayCRED

Composition vs Inheritance - Favour Composition, Why & When

Choose your preparation mode3 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
🎯
Composition vs Inheritance - Favour Composition, Why & When
mediumOOPAmazonGoogleMicrosoft

Imagine building a car software system where you want to add new features without breaking existing ones. Should you inherit from a base car class or compose smaller feature modules? This dilemma highlights the importance of choosing between inheritance and composition.

💡 Beginners often confuse inheritance as the default way to reuse code and model relationships, overlooking how it can tightly couple classes and reduce flexibility.
📋
Interview Question

Explain the difference between composition and inheritance in object-oriented design. Why is composition often preferred over inheritance? When should you favour one over the other?

is-a vs has-a relationshipscoupling and flexibility in designcode reuse and maintainability
💡
Scenario & Trace
ScenarioDesigning a game character system where characters can have different abilities like flying, swimming, or shooting.
Using inheritance, you might create subclasses like FlyingCharacter, SwimmingCharacter, etc., leading to a complex hierarchy. Using composition, you create a Character class that contains Ability objects (FlyAbility, SwimAbility), allowing dynamic addition/removal of abilities without changing the class hierarchy.
ScenarioBuilding a UI framework where buttons and text fields share common behaviors but also have unique features.
Inheritance might force all UI elements into a rigid hierarchy, making it hard to add new behaviors. Composition allows UI elements to include behavior components (e.g., Clickable, Draggable), promoting reuse and flexibility.
  • When a subclass needs to override multiple behaviors from the parent class → inheritance can cause fragile base class problems
  • When runtime behavior needs to change dynamically → composition supports this better than static inheritance
  • When the domain naturally fits an 'is-a' relationship with stable hierarchy → inheritance might be simpler and more intuitive
⚠️
Common Mistakes
Thinking inheritance is always better for code reuse

Interviewer suspects lack of understanding of coupling and flexibility issues

Explain that inheritance can cause tight coupling and fragile designs; composition offers more flexible reuse

Confusing 'is-a' and 'has-a' relationships

Interviewer doubts your grasp of fundamental OOP relationships

Clarify that inheritance models 'is-a' and composition models 'has-a' relationships

Ignoring runtime flexibility benefits of composition

Interviewer thinks you lack practical design experience

Highlight how composition allows changing behavior dynamically by swapping components

Assuming inheritance is always simpler

Interviewer questions your understanding of maintenance and scalability

Discuss how inheritance hierarchies can become complex and brittle, making maintenance harder

🧠
Basic Definition - What It Is
💡 This level covers the fundamental difference and basic intuition behind the two concepts.

Intuition

Inheritance models an 'is-a' relationship by extending a class, while composition models a 'has-a' relationship by including objects.

Explanation

Inheritance allows a class to inherit properties and behaviors from a parent class, establishing a tight relationship and enabling code reuse. Composition involves building classes by combining objects of other classes, promoting flexibility by delegating responsibilities. Favoring composition helps avoid deep inheritance hierarchies and reduces coupling, making systems easier to maintain and extend.

Memory Hook

💡 Think of inheritance as a family tree (child is a type of parent), and composition as assembling a toolkit (an object has tools it uses).

Interview Questions

What is the main difference between inheritance and composition?
  • Inheritance is an 'is-a' relationship
  • Composition is a 'has-a' relationship
  • Composition promotes looser coupling
Depth Level
Interview Time30 seconds
Depthbasic

Covers fundamental definitions and intuition; sufficient for quick screening questions.

Interview Target: Minimum floor - never go below this

Knowing only this will help you pass initial screening but not detailed design discussions.

🧠
Mechanism Depth - How It Works
💡 This level explains internal design trade-offs and practical implications expected in product company interviews.

Intuition

Composition enables flexible behavior by delegating responsibilities to contained objects, while inheritance creates a fixed class hierarchy that can be fragile and tightly coupled.

Explanation

Inheritance tightly couples child classes to parent implementations, making changes in the parent ripple through subclasses, which can cause fragility and limit reuse. Composition, by contrast, uses object references to delegate tasks, allowing behaviors to be changed at runtime or replaced without affecting the containing class. This reduces coupling and increases modularity. Favoring composition aligns with design principles like SOLID, especially the Open/Closed Principle and Dependency Inversion Principle. However, inheritance is still useful when there is a clear, stable 'is-a' relationship and shared behavior that should be enforced.

Memory Hook

💡 Composition is like building with LEGO blocks you can rearrange anytime; inheritance is like carving a sculpture from a single block.

Interview Questions

Why is composition considered more flexible than inheritance?
  • Composition allows changing behavior at runtime
  • Inheritance creates tight coupling and fragile hierarchies
  • Composition supports better code reuse through delegation
When would you still use inheritance over composition?
  • When there is a clear 'is-a' relationship
  • When behavior is stable and unlikely to change
  • When you want to enforce a common interface or contract
Depth Level
Interview Time2-3 minutes
Depthintermediate

Demonstrates understanding of design trade-offs, coupling, and maintainability; suitable for FAANG on-sites.

Interview Target: Target level for FAANG on-sites

Mastering this level distinguishes you from most candidates and prepares you for system design discussions.

📊
Explanation Depth Levels
💡 Choose your explanation depth based on interview stage and company expectations.
LevelInterview TimeSuitable ForRisk
Basic Definition30sScreening call or quick conceptual questionsToo shallow for detailed design or system architecture interviews
Mechanism Depth2-3 minutesOn-site interviews at FAANG and top product companiesRequires good understanding of design principles and trade-offs
💼
Interview Strategy
💡 Use this guide to structure your explanation clearly and confidently before every mock or real interview.

How to Present

Start with a clear definition of inheritance and compositionGive a real-world analogy or example to illustrate the differenceExplain the internal mechanism and trade-offs between the twoDiscuss edge cases and when to prefer one over the other

Time Allocation

Definition: 30s → Example: 1min → Mechanism: 2min → Edge cases: 30s. Total ~4min

What the Interviewer Tests

Interviewer checks your understanding of object relationships, design flexibility, coupling, and practical application in design problems.

Common Follow-ups

  • What problems can deep inheritance hierarchies cause? → Fragility, tight coupling, difficulty in maintenance
  • How does composition support runtime behavior changes? → By delegating to contained objects that can be swapped or modified
💡 These follow-ups test your depth and ability to reason about design trade-offs.
🔍
Pattern Recognition

When to Use

Asked during OOP design, system design, or low-level design interviews when discussing class relationships and design flexibility.

Signature Phrases

Explain composition vs inheritanceCompare is-a and has-a relationshipsWhy favour composition over inheritance?

NOT This Pattern When

Similar Problems

Practice

(1/5)
1. Trace the sequence of events when a client requests a service via Dependency Injection (DI) in an IoC container. Which step correctly follows the previous?
easy
A. Client creates the service instance directly, then passes it to the IoC container.
B. Client requests the service from the IoC container, which then creates and injects dependencies into the client.
C. Service creates the client instance and injects itself into the client.
D. IoC container instantiates the service and injects it into the client before the client uses it.

Solution

  1. Step 1: Understand DI and IoC flow

    In Dependency Injection via IoC, the client requests a service from the container, which manages creation and injection.
  2. Step 2: Analyze options

    Client requests the service from the IoC container, which then creates and injects dependencies into the client. correctly describes the client requesting the service and the container creating and injecting dependencies. Client creates the service instance directly, then passes it to the IoC container. reverses roles incorrectly. IoC container instantiates the service and injects it into the client before the client uses it. suggests container injects before client requests, which is inaccurate. Service creates the client instance and injects itself into the client. incorrectly states the service creates the client.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    IoC container controls creation; client depends on container to provide dependencies.
Hint: In DI, client asks container; container creates and injects dependencies.
Common Mistakes:
  • Thinking client creates service instances directly
  • Assuming container injects dependencies before client requests
  • Confusing who controls object creation
2. You need to traverse a tree-like structure where each node can be either a single element or a composite containing multiple child elements. The traversal should allow clients to iterate over all elements uniformly without exposing the internal structure. Which design approach best fits this requirement?
easy
A. Implement the Composite pattern combined with an Iterator interface to provide a unified traversal abstraction.
B. Use a recursive brute force traversal that manually visits each node and its children.
C. Apply a greedy algorithm that visits nodes based on a heuristic to minimize traversal time.
D. Use dynamic programming to store and reuse traversal results for overlapping subtrees.

Solution

  1. Step 1: Understand the problem structure

    The problem involves a tree with nodes that can be leaves or composites containing children, requiring uniform traversal.
  2. Step 2: Identify the suitable pattern

    The Composite pattern allows treating individual objects and compositions uniformly, and combining it with an Iterator abstracts traversal details.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Composite + Iterator provides uniform traversal abstraction [OK]
Hint: Composite + Iterator unifies traversal of tree structures [OK]
Common Mistakes:
  • Confusing traversal with greedy or DP approaches
  • Using manual recursion without abstraction
3. Identify the bug in the following singleton implementation that aims to use lazy initialization with double-checked locking in Java-like pseudocode:
class Singleton {
    private static Singleton instance;

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized(Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
What is the subtle bug that can cause thread-safety issues?
medium
A. The synchronized block is too large, causing unnecessary locking overhead.
B. The instance variable is not declared volatile, risking instruction reordering.
C. The first null check outside synchronized block is redundant and should be removed.
D. The constructor is not private, allowing multiple instances externally.

Solution

  1. Step 1: Analyze double-checked locking correctness

    Without volatile, the instance reference may be visible before full construction due to instruction reordering.
  2. Step 2: Check other options

    Synchronized block size is minimal and correct; first null check is necessary for performance; constructor privacy is unrelated to this snippet.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Missing volatile causes subtle thread-safety bugs [OK]
Hint: Volatile prevents instruction reordering in double-checked locking [OK]
Common Mistakes:
  • Ignoring volatile keyword necessity
  • Thinking synchronized block size is the bug
  • Assuming constructor privacy is the main issue here
4. Examine the following buggy code implementing the Template Method Pattern. Which line contains the subtle bug that breaks the pattern's intended behavior?
medium
A. Line overriding prepare_recipe in Tea subclass
B. Line defining abstract method brew in base class
C. Line calling add_condiments inside prepare_recipe base method
D. Line overriding customer_wants_condiments in Tea subclass

Solution

  1. Step 1: Identify overridden methods

    Tea overrides prepare_recipe, which breaks the template method pattern by duplicating and changing the algorithm flow.
  2. Step 2: Understand impact

    Overriding the template method in subclass bypasses the base class skeleton, causing inconsistent behavior and code duplication.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Template method must not be overridden by subclasses [OK]
Hint: Overriding template method breaks algorithm skeleton [OK]
Common Mistakes:
  • Thinking overriding abstract methods is bug
  • Ignoring hook method usage
5. If a new requirement arises where an interface needs to add a method without breaking existing implementations, what is the best approach to handle this in a language that originally did not support default methods in interfaces?
hard
A. Add the method to the interface and require all implementers to update their code immediately.
B. Create a new interface that extends the original and adds the new method, then update clients to use the new interface.
C. Add the method as a static method in the interface.
D. Convert the interface into an abstract class and provide a default implementation for the new method.

Solution

  1. Step 1: Understand backward compatibility

    Adding a method directly to an interface breaks existing implementers if no default implementation exists.
  2. Step 2: Why converting to abstract class is problematic

    Changing interface to abstract class breaks existing multiple inheritance and design contracts.
  3. Step 3: Using interface extension

    Creating a new interface that extends the original preserves backward compatibility and allows gradual adoption.
  4. Step 4: Static methods in interfaces

    Static methods do not affect instance method contracts and cannot replace instance methods.
  5. Final Answer:

    Option B -> Option B
  6. Quick Check:

    Extending interfaces is the safe way to evolve contracts without breaking clients.
Hint: Extend interfaces to add methods without breaking existing code.
Common Mistakes:
  • Assuming all implementers can update immediately.
  • Thinking abstract classes can replace interfaces without impact.
  • Confusing static methods with instance methods in interfaces.