Design PatternsIntermediate.15 min read

Composite Pattern

Represent part-whole hierarchies as trees and let clients treat individual objects and groups through one common interface.

StructuralJavaTree StructureComposition
Composite Pattern infographic showing FileSystem component, File leaf and Folder composite in a tree
The supplied file-system example models individual files and folders through a shared FileSystem interface.

Concept Overview

The Composite pattern composes objects into tree structures to represent part-whole hierarchies. It lets clients treat individual objects and groups uniformly through a common Component interface. The supplied infographic uses a file system: File is a leaf, Folder is a composite that stores child FileSystem elements, and the client calls showDetails() without needing separate top-level logic for files and folders.

1. The problem: clients handle leaves and groups differently

A client may need to process one file or a folder containing many files. Without a common abstraction, the client repeatedly checks whether an object is a file or folder and implements different behaviour for each. As nested folders are introduced, this conditional logic can become recursive and spread throughout the application. The Composite pattern moves the tree structure and recursive delegation into the composite objects.

2. Participants: Component, Leaf and Composite

The Component declares the common operation. A Leaf represents an individual object and has no children. A Composite stores child Components and delegates the operation to them, often recursively. The Client works with the Component interface. In the supplied example, FileSystem is the Component, File is the Leaf and Folder is the Composite.

FileSystem component and Folder compositejava
interface FileSystem {
    void showDetails();
}

final class File implements FileSystem {
    private final String name;

    File(String name) { this.name = name; }

    public void showDetails() {
        System.out.println("File: " + name);
    }
}

final class Folder implements FileSystem {
    private final String name;
    private final List<FileSystem> children = new ArrayList<>();

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

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

    public void showDetails() {
        System.out.println("Folder: " + name);
        children.forEach(FileSystem::showDetails);
    }
}

3. Uniform client handling

The client can store a File and a Folder in a collection of FileSystem objects and call showDetails() on each. It does not need a separate traversal algorithm for every concrete type. When a folder receives the operation, it forwards the call to each child. If a child is another folder, that folder repeats the same process, naturally traversing the hierarchy.

4. Safety and API design choices

A Composite implementation must decide whether child-management methods such as add() belong on the common Component interface or only on Composite. Putting them on Component makes uniform use easier but gives leaves operations they cannot meaningfully support. Keeping them only on Composite preserves a smaller leaf contract but may require the client to know when it has a composite. The appropriate choice depends on whether transparency or type safety is more important to the API.

5. Real-world uses and trade-offs

File systems, organisation charts, UI component trees, menu structures and expression trees are natural hierarchical examples. Composite supports recursive structures and uniform client handling, and new leaf types can often be added without changing the client. The trade-off is that a broad Component interface may be difficult to design, and unrestricted child operations can permit invalid tree structures unless constraints are enforced.

Key Takeaways

  • ✓Composite represents part-whole hierarchies as trees.
  • ✓Leaf and Composite share a Component interface.
  • ✓Composite delegates operations recursively to its children.
  • ✓Choose deliberately between a transparent Component API and a type-safe child-management API.