Back to LLD explorer
Structural Design• Patterns: Composite, Command, Iterator

File System

Medium

Problem Summary

Design an In-Memory File System hierarchy supporting nested directories, files, path resolution, recursive disk usage calculation, and transactional commands.

Functional Scope

  • Hierarchical representation of Files and Directories under a root directory ('/').
  • Path navigation and creation (`mkdir`, `touch`, `ls`, `cat`).
  • Recursive calculation of directory size using the Composite pattern.
  • Search files matching name prefixes or extensions.
  • Thread safety for concurrent reads and writes across branches.

Entity-Relationship (ER) Schema

FileSystemNode <|-- File
FileSystemNode <|-- Directory
Directory [1] --> [*] FileSystemNode
FileSystem [1] --> [1] Directory (Root)

Design Approach

Apply the Composite pattern to treat files and directories uniformly. Calculating directory sizes or generating recursive tree layouts traverses node trees polymorphically without type checks.

Core Classes & Models

FileSystemNode (Abstract component: getName, getSize, isDirectory)File (Leaf node with byte content)Directory (Composite node holding children map)FileSystem (Facade managing path parsing and current working directory)FileSystemCommand (Command pattern for mkdir, rm, mv with undo support)
Code Blueprint
97 lines
/**
 * Low-Level Design: In-Memory File System
 * Design Patterns Applied:
 *  - Composite Pattern: Treating File (Leaf) and Directory (Composite) uniformly under Entry interface
 *  - Command Pattern: Encapsulating file operations (Create, Write, Delete, Undo) as executable objects
 *  - Iterator Pattern: Navigating hierarchical folder structures recursively
 */

import java.util.*;

// --- [DESIGN PATTERN: Composite] Component interface ---
interface FileSystemEntry {
    String getName();
    int getSize();
    void printHierarchy(String indent);
}

class FileEntry implements FileSystemEntry {
    private final String name;
    private String content;

    public FileEntry(String name, String content) {
        this.name = name; this.content = content;
    }
    public void setContent(String content) { this.content = content; }
    public String getContent() { return content; }
    @Override public String getName() { return name; }
    @Override public int getSize() { return content.length(); }
    @Override public void printHierarchy(String indent) {
        System.out.println(indent + "📄 " + name + " (" + getSize() + " bytes)");
    }
}

class DirectoryEntry implements FileSystemEntry {
    private final String name;
    private final Map<String, FileSystemEntry> children = new LinkedHashMap<>();

    public DirectoryEntry(String name) { this.name = name; }
    @Override public String getName() { return name; }

    public void addEntry(FileSystemEntry entry) { children.put(entry.getName(), entry); }
    public void removeEntry(String name) { children.remove(name); }
    public FileSystemEntry getChild(String name) { return children.get(name); }

    @Override
    public int getSize() {
        int total = 0;
        for (FileSystemEntry child : children.values()) total += child.getSize();
        return total;
    }

    @Override
    public void printHierarchy(String indent) {
        System.out.println(indent + "📁 " + name + "/ (" + getSize() + " bytes)");
        for (FileSystemEntry child : children.values()) {
            child.printHierarchy(indent + "  ");
        }
    }
}

// --- [DESIGN PATTERN: Command] Command interface for file operations ---
interface FileCommand {
    void execute();
    void undo();
}

class CreateFileCommand implements FileCommand {
    private final DirectoryEntry parent;
    private final FileEntry file;

    public CreateFileCommand(DirectoryEntry parent, String fileName, String content) {
        this.parent = parent;
        this.file = new FileEntry(fileName, content);
    }
    @Override public void execute() { parent.addEntry(file); }
    @Override public void undo() { parent.removeEntry(file.getName()); }
}

public class Main {
    public static void main(String[] args) {
        DirectoryEntry root = new DirectoryEntry("root");
        DirectoryEntry etc = new DirectoryEntry("etc");
        DirectoryEntry var = new DirectoryEntry("var");

        root.addEntry(etc);
        root.addEntry(var);

        FileCommand cmd = new CreateFileCommand(etc, "hosts", "127.0.0.1 localhost");
        cmd.execute();

        FileCommand cmd2 = new CreateFileCommand(var, "sys.log", "[INFO] Booting OS kernel");
        cmd2.execute();

        System.out.println("--- In-Memory File System Hierarchy ---");
        root.printHierarchy("");
    }
}