Design Patterns Simplified: Part 19 — Composite Pattern (a.k.a. “The File Tree Organizer”)



This content originally appeared on DEV Community and was authored by Prateek Prabhakar

The Composite Pattern belongs to the Structural category of design patterns.
Why? Because it allows you to treat individual objects and groups of objects uniformly, by organizing them into a tree like hierarchy.

Think about a Company Org Chart.

  • An Employee can be a individual contributor.
  • A Manager is also an employee, but they can have multiple employees reporting to them.

Now, when their details are needed in order to distribute festive coupons, you don’t want different logic for developers and managers. You would just want to call the same method, and the right thing should happen.

This is exactly what the Composite Pattern does in code. It lets you work with single objects (referred as leaves) and collections of objects (referred as composites) through a common interface.

The File System

Suppose you are building a file explorer application. You want it to be able to display both Files and Folders.
But a Folder can contain Files as well as other Folders, and you don’t want to write separate logic for each.

So, the challenge here is – How do you treat individual items and groups of items in the same way?

Enter the Composite Pattern. It lets you represent part-whole hierarchies (like trees) where individual objects and groups are treated uniformly.

What does the code look like?

// Step 1: Define a common interface
Interface FileSystemItem
    Method Display(indentLevel)

// Step 2: Leaf class (File)
Class File implements FileSystemItem
    Property name

    Constructor(name)
        this.name = name

    Method Display(indentLevel)
        Print indentLevel * "-" + " File: " + name

// Step 3: Composite class (Folder)
Class Folder implements FileSystemItem
    Property name
    Property items = List of FileSystemItem

    Constructor(name)
        this.name = name

    Method Add(item)
        items.Add(item)

    Method Display(indentLevel)
        Print indentLevel * "-" + " Folder: " + name
        For each item in items
            item.Display(indentLevel + 1)

// caller logic
root = new Folder("Root")
root.Add(new File("Resume.docx"))
root.Add(new File("Budget.xlsx"))

projects = new Folder("Projects")
projects.Add(new File("AppDesign.pdf"))
projects.Add(new File("Prototype.png"))

root.Add(projects)

root.Display(0)

//output
Folder: Root
- File: Resume.docx
- File: Budget.xlsx
- Folder: Projects
-- File: AppDesign.pdf
-- File: Prototype.png

In the above code, we define a common interface FileSystemItem and both File and Folder implement the same interface. This ensures we can call Display() on either of them without worrying about whether it is a file or a folder.

We have a Leaf (File) which represents a single object (like Resume.docx). The Display() method just prints its own name with indentation.

There is another class Composite (Folder) that holds a collection of FileSystemItem(both files and folders). Its Display() method first prints the folder name, then recursively calls Display() on each child item.

This recursive call builds the tree-like structure.

In short, the Composite Pattern hides the complexity of “is this a single item or a group?”. You just treat everything as a FileSystemItem. The recursion inside Folder handles the hierarchy behind the scenes.

What Did We Achieve?

  • Unified treatment: Files and Folders can be handled with the same operations.
  • Scalability: You can add new types (like shortcuts, archives) easily without breaking existing code.
  • Tree structures: Perfect for hierarchical data like file systems, menus, or org charts.

When Should You Use the Composite Pattern?

  • When your objects naturally form a tree structure (like files, menus, or employees).
  • When you want to treat individual and composite objects uniformly.
  • When you want to simplify client code by avoiding if-else checks for single vs group.
  • When new leaf or composite types should be easy to add without changing client logic.

Use Cases?

  • File Systems (Files and Folders)
  • UI Components (Buttons, Panels, Windows)
  • Organization Structures (Employee vs Manager hierarchy)
  • Menu Systems (Single menu item vs Submenu)

To summarize, it would be apt to say,

The Composite Pattern is like your File Tree. You don’t care whether you are dealing with a single File or a whole Folder. Both are items, and you can work with them in the same way.

This keeps your code simple, extensible, and a lot cleaner whenever hierarchical structures come into play.

Composite works hand in hand with the Iterator Pattern.
We will be diving into it next.. Stay Tuned!


This content originally appeared on DEV Community and was authored by Prateek Prabhakar