Design Pattern

Composite Pattern

Clean Java-only production-ready implementation.


What Problem It Solves

You have a tree structure (file system: directories contain files or subdirectories). Operations like getSize() or display() should work identically on a leaf (file) and a container (directory).

Where Composite Appears in LLD Problems

  • File System (#20): The entire problem IS a composite pattern โ€” files (leaf) and directories (composite)
  • Organization Hierarchy: Employee (leaf) and Department (composite) with common getSalary() or getHeadcount()
  • Menu System: MenuItem (leaf) and Menu (composite with sub-menus)
  • HTML DOM: HTML elements form a composite tree

Implementation

// โ”€โ”€โ”€ EXAMPLE 1 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
// WHAT WE ARE IMPLEMENTING:
// A folder/file explorer calculating size on disk across nested structures.
//
// WHERE THE COMPONENT FITS IN:
// FileSystemNode is the Component. File is the Leaf. Directory represents the
// Composite containing lists of child nodes.
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
import java.util.ArrayList;
import java.util.List;

// --- Component ---
interface FileSystemNode {
    String getName();
    int getSize();
    void display(String indent);
}

// --- Leaf ---
class FileNode implements FileSystemNode {
    private final String name;
    private final int size;

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

    public String getName() { return name; }
    public int getSize() { return size; }
    public void display(String indent) { System.out.println(indent + "๐Ÿ“„ " + name + " (" + size + " bytes)"); }
}

// --- Composite ---
class DirectoryNode implements FileSystemNode {
    private final String name;
    private final List<FileSystemNode> children = new ArrayList<>();

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

    public void add(FileSystemNode node) { children.add(node); }
    public void remove(FileSystemNode node) { children.remove(node); }

    public String getName() { return name; }

    public int getSize() {
        return children.stream().mapToInt(FileSystemNode::getSize).sum();
    }

    public void display(String indent) {
        System.out.println(indent + "๐Ÿ“ " + name + "/ (" + getSize() + " bytes)");
        for (FileSystemNode child : children) {
            child.display(indent + "  ");
        }
    }
}

public class Main {
    public static void main(String[] args) {
        // Build tree
        DirectoryNode root = new DirectoryNode("root");

        DirectoryNode docs = new DirectoryNode("docs");
        docs.add(new FileNode("readme.md", 500));
        docs.add(new FileNode("guide.pdf", 2000));

        DirectoryNode src = new DirectoryNode("src");
        src.add(new FileNode("main.java", 1200));
        src.add(new FileNode("utils.java", 800));

        root.add(docs);
        root.add(src);
        root.add(new FileNode(".gitignore", 50));

        // Uniform operation on tree
        root.display("");
        System.out.println("\nTotal size: " + root.getSize() + " bytes");
    }
}

๐Ÿ’ฌReview

Help Us Improve

How helpful was this walkthrough?

Click a star to rate. We actively use this feedback to refine and update our system design content.

Placeholder
Optional but highly appreciated!

Discussion

Share your thoughts, ask questions, or help others.

Loading comments...