Design Pattern

Composite Pattern

Clean Java-only production-ready implementation.


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).

// ─── 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");
    }
}