Skip to content
Low Level Design Mastery Logo
LowLevelDesign Mastery

Composite Pattern

Compose objects into tree structures - treat individual objects and compositions uniformly!

Now let’s explore the Composite Pattern - a powerful structural design pattern that lets you compose objects into tree structures and work with them uniformly.

Imagine you’re organizing files and folders on your computer. A folder can contain files AND other folders. When you want to get the total size, you need to treat both files and folders the same way - folders recursively sum up their contents. The Composite Pattern makes this possible by treating individual objects (files) and compositions (folders) uniformly.

The Composite Pattern composes objects into tree structures to represent part-whole hierarchies. It lets clients treat individual objects and compositions of objects uniformly.

The Composite Pattern is useful when:

  1. You want to represent part-whole hierarchies - Objects that contain other objects
  2. You want clients to ignore - The difference between individual objects and compositions
  3. You want to treat objects uniformly - Same interface for leaves and composites
  4. You have tree structures - Hierarchical data that needs uniform treatment
  5. You want recursive operations - Operations that work on both leaves and composites

What Happens If We Don’t Use Composite Pattern?

Section titled “What Happens If We Don’t Use Composite Pattern?”

Without the Composite Pattern, you might:

  • Type checking everywhere - Need to check if object is leaf or composite
  • Different interfaces - Leaves and composites have different methods
  • Complex client code - Clients need to handle leaves and composites differently
  • Code duplication - Similar logic repeated for leaves and composites
  • Hard to extend - Adding new types requires changes everywhere

Let’s start with a super simple example that anyone can understand!

Diagram

Here’s how the Composite Pattern works in practice - showing how leaves and composites work uniformly:

sequenceDiagram
    participant Client
    participant Folder as Folder (Composite)
    participant File1 as File1 (Leaf)
    participant File2 as File2 (Leaf)
    participant SubFolder as SubFolder (Composite)
    
    Client->>Folder: get_size()
    activate Folder
    Folder->>File1: get_size()
    activate File1
    File1-->>Folder: 100 bytes
    deactivate File1
    Folder->>File2: get_size()
    activate File2
    File2-->>Folder: 200 bytes
    deactivate File2
    Folder->>SubFolder: get_size()
    activate SubFolder
    SubFolder-->>Folder: 150 bytes
    deactivate SubFolder
    Folder->>Folder: Sum: 100 + 200 + 150
    Folder-->>Client: 450 bytes
    deactivate Folder
    
    Note over Client,SubFolder: Client treats File and Folder\nthe same way - uniform interface!

You’re building a file system. You have files (individual objects) and folders (containers). Without Composite Pattern:

Problems:

  • Different interfaces - Files and folders handled differently
  • Type checking - Clients need to check if object is file or folder
  • Can’t treat uniformly - No common interface
  • Hard to extend - Adding new types requires changes everywhere
classDiagram
    class Component {
        <<interface>>
        +get_size() int
        +get_name() string
    }
    class File {
        -name: string
        -size: int
        +get_size() int
        +get_name() string
    }
    class Folder {
        -name: string
        -children: List~Component~
        +get_size() int
        +get_name() string
        +add(component) void
        +remove(component) void
    }
    
    Component <|.. File : implements (leaf)
    Component <|.. Folder : implements (composite)
    Folder --> Component : contains (children)
    
    note for Component "Common interface for leaves and composites"
    note for File "Leaf - individual object"
    note for Folder "Composite - contains components"

Real-World Software Example: Organization Hierarchy

Section titled “Real-World Software Example: Organization Hierarchy”

Now let’s see a realistic software example - an organization system that needs to calculate total salary for employees and departments.

You’re building an HR system that needs to calculate total salary. Employees can be individual workers or managers (who have subordinates). Without Composite Pattern:

Problems:

  • Different interfaces - Employees and managers handled differently
  • Type checking - Need to check if object is employee or manager
  • Can’t treat uniformly - No common interface

There are different ways to implement the Composite Pattern:

All methods in component interface, leaves implement empty methods for composite operations:

Pros: Uniform interface, no type checking needed
Cons: Leaves have methods they don’t use (can raise exceptions)

Only leaf operations in component interface, composite operations in composite class:

Pros: Type-safe, leaves don’t have unused methods
Cons: Need type checking to use composite operations


Use Composite Pattern when:

You want to represent part-whole hierarchies - Objects that contain other objects
You want clients to ignore - The difference between individual objects and compositions
You want to treat objects uniformly - Same interface for leaves and composites
You have tree structures - Hierarchical data that needs uniform treatment
You want recursive operations - Operations that work on both leaves and composites

Don’t use Composite Pattern when:

Simple flat structure - No hierarchy, just a list
Different operations - Leaves and composites need very different operations
Performance critical - Recursive operations can be slower
Over-engineering - Don’t add complexity for simple cases


Mistake 2: Composite Not Delegating to Children

Section titled “Mistake 2: Composite Not Delegating to Children”

  1. Uniform Treatment - Clients treat leaves and composites uniformly
  2. No Type Checking - Client doesn’t need to check if object is leaf or composite
  3. Recursive Operations - Operations work naturally on tree structures
  4. Easy to Extend - Add new component types easily
  5. Tree Structures - Natural representation of hierarchies
  6. Simplified Client Code - Client code is simpler and cleaner

Composite Pattern is a structural design pattern that composes objects into tree structures to represent part-whole hierarchies. It lets clients treat individual objects and compositions of objects uniformly.

  • Uniform treatment - Treat leaves and composites the same way
  • No type checking - Client doesn’t need to check types
  • Recursive operations - Operations work on tree structures naturally
  • Tree structures - Perfect for hierarchical data
  • Simplified code - Client code is simpler
  1. Define component interface - Common interface for leaves and composites
  2. Implement leaf - Individual object that implements interface
  3. Implement composite - Container that implements interface and contains components
  4. Build tree - Compose objects into tree structure
  5. Treat uniformly - Client treats all components the same way
Component (interface)
├── Leaf (implements Component)
└── Composite (implements Component, contains Components)
  • Component - Common interface for leaves and composites
  • Leaf - Individual object (e.g., File, Employee)
  • Composite - Container object (e.g., Folder, Department)
  • Client - Uses components uniformly
class Component:
def operation(self): pass
class Leaf(Component):
def operation(self):
return "Leaf"
class Composite(Component):
def __init__(self):
self.children = []
def operation(self):
return "Composite"
def add(self, component):
self.children.append(component)

✅ Represent part-whole hierarchies
✅ Want uniform treatment of leaves and composites
✅ Have tree structures
✅ Need recursive operations
✅ Want to simplify client code

❌ Simple flat structure
❌ Different operations for leaves and composites
❌ Performance critical (recursive overhead)
❌ Over-engineering simple cases

  • Composite Pattern = Treats leaves and composites uniformly
  • Component = Common interface
  • Leaf = Individual object
  • Composite = Container with children
  • Benefit = Uniform treatment, recursive operations
  • Use Case = Hierarchical structures (file systems, organizations)
class Component:
def operation(self): pass
class Leaf(Component):
def operation(self):
return "Leaf operation"
class Composite(Component):
def __init__(self):
self.children = []
def operation(self):
# Delegate to children
for child in self.children:
child.operation()
def add(self, component):
self.children.append(component)
  • Composite Pattern treats leaves and composites uniformly
  • It uses a common interface for both
  • Composite delegates operations to children
  • It’s perfect for tree structures
  • It’s about uniformity, not just containment!

What to say:

“Composite Pattern is a structural design pattern that composes objects into tree structures to represent part-whole hierarchies. It lets clients treat individual objects and compositions of objects uniformly through a common interface.”

Why it matters:

  • Shows you understand the fundamental purpose
  • Demonstrates knowledge of when to use it
  • Indicates you can explain concepts clearly

Must mention:

  • Part-whole hierarchies - Objects that contain other objects
  • Uniform treatment - Want to treat leaves and composites the same way
  • Tree structures - Hierarchical data
  • Recursive operations - Operations that work on both leaves and composites

Example scenario to give:

“I’d use Composite Pattern when building a file system. Files are leaves, folders are composites. Both implement a FileSystemComponent interface with get_size(). When I call get_size() on a folder, it recursively sums the sizes of its children. The client doesn’t need to know if it’s a file or folder - it just calls get_size() on any component.”

Must discuss:

  • Transparent Composite: All methods in interface, leaves raise exceptions for composite operations
  • Safe Composite: Only leaf operations in interface, composite operations only in composite class
  • Preference: Transparent Composite is preferred for uniformity

Example to give:

“I prefer Transparent Composite because it provides a uniform interface. All components have the same methods. Leaves raise exceptions for composite operations like add(), but the client doesn’t need to check types. Safe Composite requires type checking, which breaks the uniformity.”

Benefits to mention:

  • Uniform treatment - Clients treat leaves and composites the same way
  • No type checking - Client doesn’t need to check types
  • Recursive operations - Operations work naturally on trees
  • Easy to extend - Add new component types easily
  • Simplified code - Client code is simpler

Trade-offs to acknowledge:

  • Complexity - Adds abstraction layer
  • Performance - Recursive operations can be slower
  • Over-engineering risk - Can be overkill for simple cases

Q: “What’s the difference between Composite Pattern and Decorator Pattern?”

A:

“Composite Pattern composes objects into tree structures to represent part-whole hierarchies. Decorator Pattern adds behavior to objects dynamically. Composite is about structure and hierarchy, Decorator is about adding functionality. Composite treats leaves and composites uniformly, Decorator wraps objects to add features.”

Q: “How do you prevent circular references in Composite Pattern?”

A:

“I check if adding a component would create a cycle. Before adding a component to a composite, I traverse up the tree to see if the component already contains the composite. If it does, I raise an exception. I also prevent a composite from adding itself as a child.”

Q: “How does Composite Pattern relate to SOLID principles?”

A:

“Composite Pattern supports the Open/Closed Principle - you can add new component types without modifying existing code. It supports Single Responsibility Principle by separating leaf and composite concerns. It supports Liskov Substitution Principle - leaves and composites can be used interchangeably through the common interface. It also supports Dependency Inversion Principle by depending on the Component abstraction.”

Before your interview, make sure you can:

  • Define Composite Pattern clearly in one sentence
  • Explain when to use it (with examples showing uniform treatment)
  • Describe Transparent vs Safe Composite
  • Implement Composite Pattern from scratch
  • Compare with other structural patterns (Decorator, Bridge)
  • List benefits and trade-offs
  • Identify common mistakes (circular references, no delegation)
  • Give 2-3 real-world examples
  • Connect to SOLID principles
  • Discuss when NOT to use it
  • Explain how to prevent circular references

Remember: Composite Pattern is about treating individual objects and compositions uniformly - perfect for tree structures and hierarchies! 🌳