Bird
Raised Fist0
Interview Prepoop-design-patternsmediumAmazonGoogleMicrosoftFlipkartSwiggyRazorpayCRED

Composition vs Inheritance - Favour Composition, Why & When

Choose your preparation mode3 modes available
▶
Steps
setup

Define Base Shape Class Using Inheritance

We start by defining a base class 'Shape' with a method 'draw'. This sets up the inheritance approach where specific shapes will extend this base class.

💡 Initializing the base class is crucial because it establishes the common interface for all shapes in the inheritance model.
Line:class Shape { public void draw() {} }
💡 This step shows how inheritance begins with a common superclass defining shared behavior.
📊
Composition vs Inheritance - Favour Composition, Why & When - Watch the Algorithm Execute, Step by Step
Watching this visualization helps you understand the structural and behavioral differences between inheritance and composition without needing to read dense theory. You see how design decisions affect class relationships and extensibility.
Step 1/10
·Active fill★Answer cell
Demonstrates inheritance base class setup
Shape
+draw()
Shows subclass extending base class
Shape
+draw()
Circle
+draw()
Circle ▷ Shape (1:1)
Defines interface for composition
«interface»Renderer
+render()
Implements Renderer interface for composition
«interface»Renderer
+render()
VectorRenderer
+render()
VectorRenderer → Renderer (1:1)
Shows composition by embedding Renderer
«interface»Renderer
+render()
Shape
#renderer: Renderer
+Shape()
+draw()
Shape ◆ Renderer (1:1)
Circle uses composition via Shape
«interface»Renderer
+render()
Shape
#renderer: Renderer
+Shape()
+draw()
Circle
+Circle()
+draw()
Shape ◆ Renderer (1:1)Circle ▷ Shape (1:1)
Shows runtime composition of behavior
«interface»Renderer
+render()
VectorRenderer
+render()
Shape
#renderer: Renderer
+Shape()
+draw()
Circle
+Circle()
+draw()
VectorRenderer → Renderer (1:1)Shape ◆ Renderer (1:1)Circle ▷ Shape (1:1)
Demonstrates polymorphic method call in inheritance
Shape
+draw()
Circle
+draw()
Circle ▷ Shape (1:1)
Shows dynamic delegation in composition
Shape
#renderer: Renderer
+draw()
Circle
+draw()
VectorRenderer
+render()
Shape ◆ Renderer (1:1)Circle ▷ Shape (1:1)VectorRenderer → Renderer (1:1)
Summarizes composition benefits over inheritance
Shape
#renderer: Renderer
+draw()
Circle
+draw()
«interface»Renderer
+render()
VectorRenderer
+render()
Circle ▷ Shape (1:1)Shape ◆ Renderer (1:1)VectorRenderer → Renderer (1:1)

Key Takeaways

✓ Composition decouples behavior from class hierarchies, enabling flexible and dynamic behavior changes.

This insight is hard to see from code alone because the delegation and runtime binding are implicit; visualization makes it explicit.

✓ Inheritance tightly couples subclasses to base class interfaces, limiting extensibility and increasing fragility.

Seeing the fixed inheritance arrows and overridden methods side-by-side clarifies why inheritance can be restrictive.

✓ Using interfaces and composition promotes separation of concerns and adheres to SOLID principles.

Visualizing interfaces and composition relationships helps understand how design principles are applied in practice.

Practice

(1/5)
1. In a large software system, when would applying the Interface Segregation Principle (ISP) be most beneficial?
easy
A. When clients depend on interfaces that contain methods they do not use, causing unnecessary implementation burden.
B. When all clients require the exact same set of methods, so a single fat interface simplifies design.
C. When you want to enforce a strict inheritance hierarchy with minimal interfaces.
D. When you want to reduce the number of interfaces to simplify the codebase.

Solution

  1. Step 1: Understand ISP's goal

    ISP aims to prevent clients from depending on methods they don't use, avoiding fat interfaces that force unnecessary implementations.
  2. Step 2: Analyze options

    When clients depend on interfaces that contain methods they do not use, causing unnecessary implementation burden. correctly identifies the scenario where ISP helps by splitting fat interfaces. When all clients require the exact same set of methods, so a single fat interface simplifies design. describes a scenario where ISP is less needed. When you want to enforce a strict inheritance hierarchy with minimal interfaces. confuses inheritance hierarchy with interface segregation. When you want to reduce the number of interfaces to simplify the codebase. incorrectly assumes fewer interfaces always simplify design, ignoring interface misuse.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    ISP is about splitting interfaces to avoid forcing clients to implement unused methods.
Hint: ISP splits interfaces so clients only depend on what they use.
Common Mistakes:
  • Believing fewer interfaces always mean better design
  • Thinking ISP applies when all clients use all methods
  • Confusing ISP with inheritance hierarchy rules
2. When a new feature is added by extending a class hierarchy following the Open/Closed Principle, what is the typical sequence of events when the system executes a method call on the new subclass instance?
easy
A. The base class method is always executed first, then the subclass method overrides it afterward
B. The system duplicates the base class code inside the subclass to avoid modifying the base
C. The subclass method is invoked directly due to polymorphism, without modifying base class code
D. Both base and subclass methods execute sequentially because the base class is modified to call the subclass

Solution

  1. Step 1: Understand polymorphic dispatch

    Method calls on subclass instances invoke the subclass's overridden method directly.
  2. Step 2: Base class code remains unchanged

    The base class is closed for modification; no changes are made to call subclass methods explicitly.
  3. Step 3: Why other options are incorrect

    The base class method is always executed first, then the subclass method overrides it afterward incorrectly suggests base method runs first then subclass; Both base and subclass methods execute sequentially because the base class is modified to call the subclass implies base class modification; The system duplicates the base class code inside the subclass to avoid modifying the base suggests code duplication, violating DRY and OCP.
  4. Final Answer:

    Option C -> Option C
  5. Quick Check:

    Polymorphism enables extension without modifying base code.
Hint: Polymorphism calls subclass methods directly [OK]
Common Mistakes:
  • Assuming base method always runs first
  • Believing base class must be modified to support extension
  • Thinking code duplication is a valid OCP strategy
3. Identify the bug in the following Builder pattern code snippet that constructs a luxury house:
medium
A. get_result method returns the wrong object
B. Constructor does not initialize the House object
C. Director does not call build_roof method
D. Line with 'pass' in build_pool method lacks adding 'Pool' part

Solution

  1. Step 1: Inspect build_pool method

    The build_pool method contains only 'pass', so it does not add the 'Pool' part to the house.
  2. Step 2: Check Director.construct_luxury_house calls

    The Director calls build_pool expecting the pool to be added, but due to missing implementation, it is not.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Missing pool addition causes incomplete luxury house [OK]
Hint: Empty build_pool method -> missing part added [OK]
Common Mistakes:
  • Confusing constructor initialization
  • Ignoring missing method implementation
4. What is a common trade-off or limitation when applying Dependency Inversion Principle (DIP) with heavy use of Dependency Injection frameworks?
medium
A. It always improves runtime performance by reducing object creation overhead.
B. It eliminates the need for interfaces or abstractions entirely.
C. It can increase complexity and reduce code readability due to indirect dependencies and configuration.
D. It guarantees compile-time safety without any runtime errors.

Solution

  1. Step 1: Understand DIP and DI trade-offs

    While DIP and DI improve modularity, heavy use of DI frameworks can add complexity and obscure dependencies.
  2. Step 2: Analyze options

    It can increase complexity and reduce code readability due to indirect dependencies and configuration. correctly identifies increased complexity and reduced readability as a trade-off. It always improves runtime performance by reducing object creation overhead. is false; DI can add runtime overhead. It eliminates the need for interfaces or abstractions entirely. is wrong; DIP requires abstractions. It guarantees compile-time safety without any runtime errors. is incorrect; runtime errors can still occur due to misconfiguration.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    DI frameworks improve flexibility but can complicate understanding and debugging.
Hint: DI improves modularity but can complicate code and configs.
Common Mistakes:
  • Assuming DI always improves performance
  • Believing DIP removes need for interfaces
  • Thinking DI guarantees no runtime errors
5. If the Composite pattern iterator is extended to allow reusing leaf components multiple times during traversal (e.g., shared leaves), which modification is necessary to ensure correct iteration without infinite loops?
hard
A. No change needed; the existing iterator handles reuse naturally.
B. Modify the iterator to push children in original order instead of reversed order.
C. Add a visited set to track and skip already visited components during iteration.
D. Convert the iterator to a recursive traversal to handle reuse correctly.

Solution

  1. Step 1: Understand reuse implications

    Reusing leaves means the same component can appear multiple times, risking infinite loops.
  2. Step 2: Identify solution to prevent infinite loops

    Tracking visited components prevents revisiting the same node repeatedly during iteration.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Visited set avoids infinite loops with shared components [OK]
Hint: Track visited nodes to handle shared components safely [OK]
Common Mistakes:
  • Assuming no changes needed
  • Changing push order does not fix reuse loops
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard