0
0
LLDsystem_design~7 mins

Composite pattern in LLD - System Design Guide

Choose your learning style9 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.