Java

Composition Over Inheritance

"Favor composition over inheritance" is one of the most cited principles in object-oriented design, yet inheritance remains overused. This article explores practical patterns for achieving flexibility through composition: delegation, decorator, composite, and mixins.

📋 At a Glance

AspectDetails
Patterns CoveredDelegation, Decorator, Composite, Forwarding
Primary BenefitFlexible runtime behavior, reduced coupling
Trade-offsMore objects, indirection
Java FeaturesDefault methods, Records

🎯 What You'll Learn

  • Delegation Pattern for forwarding behavior
  • Decorator Pattern for adding responsibilities dynamically
  • Composite Pattern for tree structures
  • Mixin simulation with default methods
  • When inheritance is still appropriate

Production Story: The Inheritance Nightmare

A payment processing system started with a simple hierarchy:

JAVA(4 lines)
Code
Loading syntax highlighter...

Three years later:

JAVA(9 lines)
Code
Loading syntax highlighter...
The problems:
  • Diamond inheritance problem (Java doesn't support multiple inheritance)
  • Changes to Payment broke all 15 subclasses
  • Testing required understanding entire hierarchy
  • Adding new features required new subclasses
The fix: Composition with decorators:
JAVA(15 lines)
Code
Loading syntax highlighter...

Mental Model: Inheritance vs Composition

TEXT(37 lines)
Code
Loading syntax highlighter...

🔬 Deep Dive

Pattern 1: Delegation

Use when: You want to reuse behavior without inheritance.
JAVA(37 lines)
Code
Loading syntax highlighter...
Forwarding Class Pattern:
JAVA(31 lines)
Code
Loading syntax highlighter...

Pattern 2: Decorator Pattern

Use when: Adding responsibilities to objects dynamically without modifying their class.
JAVA(91 lines)
Code
Loading syntax highlighter...
Real-World Example: InputStream Decorators:
JAVA(9 lines)
Code
Loading syntax highlighter...

Pattern 3: Composite Pattern

Use when: Treating individual objects and compositions uniformly (tree structures).
JAVA(95 lines)
Code
Loading syntax highlighter...

Pattern 4: Mixins with Default Methods

Use when: Sharing behavior across unrelated classes.
JAVA(53 lines)
Code
Loading syntax highlighter...
Another example - behavior mixins:
JAVA(55 lines)
Code
Loading syntax highlighter...

Pattern 5: Strategy as Composition

Use when: Behavior varies independently of the object using it.
JAVA(48 lines)
Code
Loading syntax highlighter...

When to Use Inheritance

Inheritance is appropriate when:

JAVA(48 lines)
Code
Loading syntax highlighter...

Decision Guide: Inheritance vs Composition

TEXT(32 lines)
Code
Loading syntax highlighter...

⚠️ Common Mistakes

Mistake 1: Inheriting for Code Reuse Only

JAVA(24 lines)
Code
Loading syntax highlighter...

Mistake 2: Deep Inheritance Hierarchies

JAVA(14 lines)
Code
Loading syntax highlighter...

🐛 Debug This: The Decorator Disaster

A developer reports: "Our logging decorator works fine alone, but when we combine it with the caching decorator, the logs show incorrect values!"

JAVA(53 lines)
Code
Loading syntax highlighter...
Why does decorator order matter here, and what's the hidden bug?

✅ Solution:
The bug is in LoggingDecorator.getData() - it calls delegate.getData(key) twice:
  1. Once to get the result for logging
  2. Once again to return the value

This causes:

  • With LoggingDecorator → CachingDecorator: First call hits cache miss, second call gets cached value (different!)
  • With CachingDecorator → LoggingDecorator: Each call to logging generates two database calls
Correct implementation:
JAVA(14 lines)
Code
Loading syntax highlighter...
The lesson: In decorator pattern, always call the delegate exactly once and reuse the result. Multiple calls can cause subtle bugs especially with caching, counting, or side-effect decorators.

💻 Exercises

Exercise 1: Forwarding Wrapper

⭐ Difficulty: Easy | ⏱️ Time: 15 minutes

Task: Create a forwarding wrapper that adds size tracking to any List.
JAVA(11 lines)
Code
Loading syntax highlighter...
✅ Solution:
JAVA(45 lines)
Code
Loading syntax highlighter...

Exercise 2: Decorator Chain

⭐⭐ Difficulty: Medium | ⏱️ Time: 20 minutes

Task: Implement a text processing pipeline using decorators.
JAVA(18 lines)
Code
Loading syntax highlighter...
✅ Solution:
JAVA(60 lines)
Code
Loading syntax highlighter...

Exercise 3: Composite File System

⭐⭐ Difficulty: Medium | ⏱️ Time: 25 minutes

Task: Implement a composite pattern for a file system that calculates total size.
JAVA(25 lines)
Code
Loading syntax highlighter...
✅ Solution:
JAVA(61 lines)
Code
Loading syntax highlighter...

Exercise 4: Mixin Interfaces

⭐⭐⭐ Difficulty: Medium-Hard | ⏱️ Time: 20 minutes

Task: Create mixin interfaces for common entity behaviors.
JAVA(20 lines)
Code
Loading syntax highlighter...
✅ Solution:
JAVA(56 lines)
Code
Loading syntax highlighter...

Exercise 5: Refactor Inheritance to Composition

⭐⭐⭐⭐ Difficulty: Hard | ⏱️ Time: 30 minutes

Task: Refactor this problematic inheritance hierarchy to use composition.
JAVA(24 lines)
Code
Loading syntax highlighter...
✅ Solution:
JAVA(106 lines)
Code
Loading syntax highlighter...

🎤 Interview Questions

Q1: Why "favor composition over inheritance"?

Answer:
  • Composition is more flexible (runtime vs compile-time)
  • Avoids tight coupling to parent class
  • Enables combining multiple behaviors
  • Easier to test (mock dependencies)
  • Doesn't break encapsulation

Q2: When is inheritance still the right choice?

Answer:
  • True "is-a" relationship that won't change
  • Framework extension points (designed for inheritance)
  • Template Method pattern (defined extension points)
  • Abstract classes with protected helpers

📝 Summary

PatternUse When
DelegationReuse behavior without inheritance
DecoratorAdd responsibilities dynamically
CompositeTree structures, uniform treatment
MixinsShare behavior across unrelated classes
StrategyBehavior varies independently
InheritanceTrue "is-a", framework extension

📅 Review Schedule for This Article

DayTaskTime
Day 1Review decision flowchart (inheritance vs composition)5 min
Day 3Redo Exercise 2 (Decorator Chain)20 min
Day 7Answer interview questions without looking10 min
Day 14Redo Debug This (Decorator Disaster)15 min
Day 30Identify one inheritance hierarchy in your codebase to refactor20 min

Next: [Part 11: Functional Clean Code]