Low Level Design

Composite Pattern — Tree Structures Treated Uniformly

How the Composite pattern lets you compose objects into tree hierarchies where individual items and groups of items share the same interface — eliminating special-case logic.

August 26, 2026·9 min read

What is the Composite Pattern?#

The Composite is a structural design pattern that lets you compose objects into tree structures to represent part-whole hierarchies, and treat individual objects and compositions of objects uniformly.

A leaf and a branch both implement the same interface. The client doesn't need to know which one it's dealing with.

You reach for Composite when:

  • You need to represent a tree-like hierarchy (file system, UI components, org charts)
  • Clients should treat individual objects and groups of objects the same way
  • You want to apply recursive operations over nested structures

Real-World Analogy#

Think of your computer's file system:

  • A file is a single unit — it has a name and a size.
  • A folder contains files and other folders — it also has a name, and its size is the sum of its contents.

Both files and folders support display() and getSize(). You can call getSize() on a folder and it recursively sums all files inside — without the caller needing to distinguish between files and folders.


Class Diagram#


Violation Code — The Problem#

java
class File {
    private String name;
    private int size;
    File(String name, int size) { this.name = name; this.size = size; }
    void display() { System.out.println("File: " + name + " (" + size + "KB)"); }
    int getSize() { return size; }
}

class Folder {
    private String name;
    private List<Object> children = new ArrayList<>();  // ❌ Object — no type safety

    void add(Object child) { children.add(child); }

    void display() {
        System.out.println("Folder: " + name);
        for (Object child : children) {
            if (child instanceof File) {                // ❌ instanceof everywhere
                ((File) child).display();
            } else if (child instanceof Folder) {
                ((Folder) child).display();
            }
        }
    }
}

Issues:

  1. No common interface — File and Folder are unrelated, stored as Object
  2. Manual type checking — instanceof checks required everywhere
  3. Violates OCP — adding a Shortcut type means updating every place that checks instanceof
  4. Tight coupling — client code must know the internal structure
  5. Not recursive — can't uniformly call operations on the whole tree

Enhanced Code — Composite Pattern#

java
// Component interface — the common contract
public interface FileSystemComponent {
    void display(String indent);
    int getSize();
}

// Leaf — a single file
public class File implements FileSystemComponent {
    private final String name;
    private final int size;

    public File(String name, int size) {
        this.name = name;
        this.size = size;
    }

    @Override
    public void display(String indent) {
        System.out.println(indent + "📄 " + name + " (" + size + " KB)");
    }

    @Override
    public int getSize() { return size; }
}

// Composite — a folder that can contain files or other folders
public class Folder implements FileSystemComponent {
    private final String name;
    private final List<FileSystemComponent> children = new ArrayList<>();

    public Folder(String name) { this.name = name; }

    public void add(FileSystemComponent component) {
        children.add(component);
    }

    @Override
    public void display(String indent) {
        System.out.println(indent + "📁 " + name + " (" + getSize() + " KB)");
        for (FileSystemComponent child : children) {
            child.display(indent + "  "); // recursive — no instanceof needed ✅
        }
    }

    @Override
    public int getSize() {
        return children.stream().mapToInt(FileSystemComponent::getSize).sum();
    }
}

// Client — treats files and folders identically
public class Main {
    public static void main(String[] args) {
        Folder root = new Folder("root");

        Folder docs = new Folder("docs");
        docs.add(new File("resume.pdf", 120));
        docs.add(new File("cover-letter.docx", 45));

        Folder src = new Folder("src");
        src.add(new File("Main.java", 8));
        src.add(new File("Utils.java", 12));

        root.add(docs);
        root.add(src);
        root.add(new File("README.md", 5));

        root.display("");
        System.out.println("Total size: " + root.getSize() + " KB");
    }
}

Output:

📁 root (190 KB)
  📁 docs (165 KB)
    📄 resume.pdf (120 KB)
    📄 cover-letter.docx (45 KB)
  📁 src (20 KB)
    📄 Main.java (8 KB)
    📄 Utils.java (12 KB)
  📄 README.md (5 KB)
Total size: 190 KB

Common LLD Problems Using Composite Pattern#

1. File System Hierarchy#

  • Components: File, Directory
  • Context: A directory contains files and subdirectories, all treated uniformly.

2. UI Component Trees#

  • Components: Button, Label, Panel, Window
  • Context: Nested UI layouts where containers hold other containers or leaf components.

3. Organisation Hierarchy#

  • Components: Employee, Manager, Director
  • Context: Managers have subordinates (employees or other managers); traversal calculates total headcount or salary.

4. Menu System#

  • Components: MenuItem, SubMenu
  • Context: Render hierarchical menus where items may contain nested submenus.

5. HTML / XML DOM Tree#

  • Components: HTMLElement, TextNode, CommentNode
  • Context: Every node is treated uniformly for traversal, rendering, or search.

6. Graphics Editor (Figma / Illustrator)#

  • Components: Line, Circle, Rectangle, Group
  • Context: Grouping shapes and applying operations (move, resize, delete) to both individual shapes and groups.

7. Access Control — Permissions#

  • Components: Permission, PermissionGroup
  • Context: Assign a group of permissions to users or roles; check any permission recursively.

8. Product Bundling in E-commerce#

  • Components: Product, Bundle
  • Context: A bundle may contain products or other bundles; total price is computed recursively.

Key Design Tip#

Design the common interface (FileSystemComponent) first. The leaf (File) ignores child-management methods; the composite (Folder) implements them. This is sometimes called the "transparency vs safety" trade-off in Composite design.


ReferencesLinks
Article ReferenceRefactoring Guru — Composite