Bird
Raised Fist0
LLDsystem_design~7 mins

Composite pattern in LLD - System Design Guide

Choose your learning style10 modes available
Problem Statement
When dealing with complex structures made of individual objects and groups of objects, treating them differently complicates code and increases errors. Without a unified way to handle single and composite objects, client code becomes cluttered with type checks and special cases.
Solution
The Composite pattern lets you treat individual objects and compositions of objects uniformly by defining a common interface. This way, clients can work with single objects and groups of objects transparently, simplifying code and enabling recursive structures.
Architecture
Component
◄───────┤ Client
↓
Leaf
↓
Leaf

This diagram shows a client interacting with a Component interface, which is implemented by both Leaf (individual objects) and Composite (groups of objects). Composite holds children Components, enabling recursive structures.

Trade-offs
✓ Pros
→
Simplifies client code by treating individual and composite objects uniformly.
→
Supports recursive tree structures naturally.
→
Makes it easy to add new kinds of components without changing client code.
✗ Cons
→
Can make the design overly general and complex if simple structures suffice.
→
Debugging can be harder due to recursive calls and indirection.
→
Performance overhead from recursive traversal and interface calls.
Use when you have tree-like hierarchical structures where clients must treat individual and composite objects uniformly, especially if the structure can grow dynamically.
Avoid when the object structure is flat or simple, or when performance is critical and recursion overhead is unacceptable.
Real World Examples
Amazon
Uses Composite pattern to represent product categories and subcategories, allowing uniform operations like display and search across single products and groups.
Adobe
In Photoshop, layers and groups of layers use Composite pattern to apply operations like move, resize, or filter uniformly.
Microsoft
Office applications use Composite pattern to manage document elements like paragraphs, tables, and images as a unified structure.
Code Example
Before applying Composite, client code must check object types to call display correctly, leading to clutter. After applying Composite, both File and Directory implement the same interface, so client code calls display uniformly without type checks.
LLD
### Before: Without Composite pattern
class File:
    def __init__(self, name):
        self.name = name
    def display(self):
        print(f"File: {self.name}")

class Directory:
    def __init__(self, name):
        self.name = name
        self.files = []
    def add_file(self, file):
        self.files.append(file)
    def display(self):
        print(f"Directory: {self.name}")
        for f in self.files:
            f.display()

# Client code
file1 = File("file1.txt")
dir1 = Directory("dir1")
dir1.add_file(file1)

for item in [file1, dir1]:
    if isinstance(item, File):
        item.display()
    else:
        item.display()


### After: With Composite pattern
from abc import ABC, abstractmethod

class Component(ABC):
    @abstractmethod
    def display(self):
        pass

class File(Component):
    def __init__(self, name):
        self.name = name
    def display(self):
        print(f"File: {self.name}")

class Directory(Component):
    def __init__(self, name):
        self.name = name
        self.children = []
    def add(self, component):
        self.children.append(component)
    def display(self):
        print(f"Directory: {self.name}")
        for child in self.children:
            child.display()

# Client code
file1 = File("file1.txt")
dir1 = Directory("dir1")
dir1.add(file1)

for item in [file1, dir1]:
    item.display()
OutputSuccess
Alternatives
Decorator pattern
Decorator adds responsibilities to objects dynamically without changing their interface, while Composite builds tree structures of objects.
Use when: Choose Decorator when you want to add features to objects without changing their structure.
Visitor pattern
Visitor separates algorithms from object structures, while Composite focuses on uniform treatment of objects and groups.
Use when: Choose Visitor when you need to perform many unrelated operations on object structures without changing them.
Summary
Composite pattern lets clients treat individual objects and groups uniformly through a common interface.
It simplifies code by removing the need for type checks and supports recursive tree structures naturally.
Use it when you have hierarchical data and want to perform operations transparently on both single and composite objects.

Practice

(1/5)
1. What is the main purpose of the Composite pattern in system design?
easy
A. To create a single instance of a class
B. To separate interface from implementation
C. To provide a way to access elements of a collection sequentially
D. To treat individual objects and compositions of objects uniformly

Solution

  1. Step 1: Understand the Composite pattern goal

    The Composite pattern allows treating individual objects and groups of objects the same way.
  2. Step 2: Compare with other design patterns

    Other options describe different patterns: Singleton (A), Iterator (D), Bridge (B).
  3. Final Answer:

    To treat individual objects and compositions of objects uniformly -> Option D
  4. Quick Check:

    Composite pattern = treat objects uniformly [OK]
Hint: Composite = treat single and group objects the same [OK]
Common Mistakes:
  • Confusing Composite with Singleton pattern
  • Thinking Composite only manages single objects
  • Mixing Composite with Iterator or Bridge patterns
2. Which of the following is the correct way to declare a composite interface method in a class diagram for the Composite pattern?
easy
A. int calculateSum(int a, int b);
B. void add(Component component);
C. String toString();
D. boolean equals(Object obj);

Solution

  1. Step 1: Identify typical Composite interface methods

    Composite pattern usually includes methods like add(), remove(), and getChild() to manage children.
  2. Step 2: Match method signature to Composite pattern

    Only void add(Component component); fits the pattern's purpose of managing child components.
  3. Final Answer:

    void add(Component component); -> Option B
  4. Quick Check:

    Composite interface method = add(Component) [OK]
Hint: Composite interface manages children with add/remove methods [OK]
Common Mistakes:
  • Choosing unrelated method signatures
  • Confusing standard Object methods with Composite methods
  • Ignoring the need to manage child components
3. Given the following code snippet in a Composite pattern implementation, what will be the output?
class Component:
  def operation(self):
    pass

class Leaf(Component):
  def operation(self):
    return "Leaf"

class Composite(Component):
  def __init__(self):
    self.children = []
  def add(self, component):
    self.children.append(component)
  def operation(self):
    results = []
    for child in self.children:
      results.append(child.operation())
    return "Composite(" + ", ".join(results) + ")"

leaf1 = Leaf()
leaf2 = Leaf()
composite = Composite()
composite.add(leaf1)
composite.add(leaf2)
print(composite.operation())
medium
A. Composite(Leaf, Leaf)
B. Leaf, Leaf
C. Composite()
D. Leaf

Solution

  1. Step 1: Understand Leaf operation output

    Each Leaf's operation returns the string "Leaf".
  2. Step 2: Understand Composite operation output

    Composite calls operation on each child and joins results with commas inside "Composite(...)".
  3. Final Answer:

    Composite(Leaf, Leaf) -> Option A
  4. Quick Check:

    Composite operation = Composite(Leaf, Leaf) [OK]
Hint: Composite operation joins child operations in parentheses [OK]
Common Mistakes:
  • Expecting just 'Leaf' output
  • Ignoring the Composite wrapper in output
  • Confusing list join syntax
4. In the following Composite pattern code, what is the main error?
class Component:
  def operation(self):
    pass

class Leaf(Component):
  def operation(self):
    return "Leaf"

class Composite(Component):
  def __init__(self):
    self.children = []
  def add(self, component):
    self.children.append(component)
  def operation(self):
    results = []
    for child in self.children:
      child.operation()
    return "Composite(" + ", ".join(results) + ")"
medium
A. The add method does not check component type
B. The Composite class does not initialize children list
C. The operation method does not collect child results
D. The Leaf class does not inherit from Component

Solution

  1. Step 1: Analyze operation method in Composite

    The loop calls child.operation() but does not append results to the list.
  2. Step 2: Identify missing result collection

    Without appending, results remains empty, causing incorrect output.
  3. Final Answer:

    The operation method does not collect child results -> Option C
  4. Quick Check:

    Missing append in loop = operation method error [OK]
Hint: Check if child results are collected in operation method [OK]
Common Mistakes:
  • Ignoring missing append to results list
  • Thinking add method type check is mandatory
  • Assuming inheritance error without evidence
5. You are designing a UI framework using the Composite pattern. You want to add a feature to calculate the total number of visible elements in a nested component tree. Which approach best fits the Composite pattern principles?
hard
A. Add a countVisible() method to the Component interface, implemented by Leaf and Composite classes
B. Use a global counter variable updated externally during rendering
C. Only count visible elements in Leaf nodes, ignoring Composite nodes
D. Traverse the tree manually outside the classes to count visible elements

Solution

  1. Step 1: Apply Composite pattern principle of uniformity

    Adding countVisible() to Component interface lets all nodes handle counting uniformly.
  2. Step 2: Implement counting in Leaf and Composite

    Leaf returns 1 if visible, 0 otherwise; Composite sums counts from children.
  3. Final Answer:

    Add a countVisible() method to the Component interface, implemented by Leaf and Composite classes -> Option A
  4. Quick Check:

    Uniform method in Component = best Composite design [OK]
Hint: Add counting method to Component interface for uniformity [OK]
Common Mistakes:
  • Using external counters breaking encapsulation
  • Counting only leaves ignoring composites
  • Manual traversal outside object methods
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