Design Patterns Composite

The Composite pattern lets you treat a single object and a group of objects the same way. You build tree-like structures where individual items and containers of items share one interface. Clients work with everything through that shared interface — they never need to check whether they are dealing with one item or many.

Composite belongs to the Structural pattern family. It is the pattern behind file systems, organizational charts, UI component trees, and document structures.

The File System Analogy

A hard drive contains folders and files. A folder can hold files or other folders. When you right-click a folder and choose "Get Size," the computer adds up the sizes of everything inside — files, nested folders, and files inside those nested folders — recursively. You do not care about the internal structure. You call getSize() on one item and get the total.

/Documents                   ← Folder (Composite)
├── resume.pdf               ← File (Leaf) — 120 KB
├── photo.jpg                ← File (Leaf) — 3.2 MB
└── /Projects                ← Folder (Composite)
    ├── plan.docx            ← File (Leaf) — 45 KB
    └── /Archive             ← Folder (Composite)
        └── old_plan.docx    ← File (Leaf) — 38 KB

getSize("/Documents") = 120 KB + 3.2 MB + 45 KB + 38 KB = 3.4 MB

Visual Diagram: Composite Tree

«interface»
Component
+--------------------+
| + getSize(): int   |
| + getName(): str   |
+--------------------+
       ▲         ▲
       |         |
     Leaf      Composite
  +---------+  +---------------------------+
  |File     |  |Folder                     |
  |---------|  |---------------------------|
  |name     |  |name                       |
  |size     |  |children: List[Component]  |
  |---------|  |---------------------------|
  |getSize()|  |add(c) / remove(c)         |
  +--------v+  |getSize() → sum of children|
               +---------------------------+

Leaf has no children.
Composite holds any mix of Leaves and other Composites.

Key Participants

Component Interface

The common contract for both individual objects and containers. Declares operations that apply to both — such as getSize(), render(), or getName().

Leaf

A single object with no children. It implements the Component interface and does the real work. A file, a button, or a single employee is a Leaf.

Composite

A container that holds a list of Components. Each Component can be a Leaf or another Composite. When the Composite receives a method call, it forwards it to all children and combines the results.

Client

Works through the Component interface. It never checks whether it is dealing with a Leaf or a Composite — it just calls the method and gets the result.

Code Walkthrough in Python

Step 1 — Define the Component Interface

class FileSystemItem:
    def get_name(self):
        raise NotImplementedError

    def get_size(self):
        raise NotImplementedError

    def display(self, indent=0):
        raise NotImplementedError

Step 2 — Create the Leaf

class File(FileSystemItem):
    def __init__(self, name, size):
        self.name = name
        self.size = size

    def get_name(self):
        return self.name

    def get_size(self):
        return self.size

    def display(self, indent=0):
        print(" " * indent + f"📄 {self.name} ({self.size} KB)")

Step 3 — Create the Composite

class Folder(FileSystemItem):
    def __init__(self, name):
        self.name = name
        self.children = []

    def add(self, item):
        self.children.append(item)

    def remove(self, item):
        self.children.remove(item)

    def get_name(self):
        return self.name

    def get_size(self):
        return sum(child.get_size() for child in self.children)

    def display(self, indent=0):
        print(" " * indent + f"📁 {self.name} ({self.get_size()} KB)")
        for child in self.children:
            child.display(indent + 4)

Step 4 — Build the Tree and Use It

root = Folder("Documents")
root.add(File("resume.pdf", 120))
root.add(File("photo.jpg", 3200))

projects = Folder("Projects")
projects.add(File("plan.docx", 45))

archive = Folder("Archive")
archive.add(File("old_plan.docx", 38))
projects.add(archive)

root.add(projects)

root.display()
print(f"Total size: {root.get_size()} KB")

Output

📁 Documents (3403 KB)
    📄 resume.pdf (120 KB)
    📄 photo.jpg (3200 KB)
    📁 Projects (83 KB)
        📄 plan.docx (45 KB)
        📁 Archive (38 KB)
            📄 old_plan.docx (38 KB)
Total size: 3403 KB

How Recursion Powers Composite

root.get_size()
  → resume.pdf.get_size()          → 120
  → photo.jpg.get_size()           → 3200
  → Projects.get_size()
      → plan.docx.get_size()       → 45
      → Archive.get_size()
          → old_plan.docx.get_size() → 38
        Archive returns 38
      Projects returns 45 + 38 = 83
  root returns 120 + 3200 + 83 = 3403

Each Composite asks its children. Children ask their children. The call travels down the tree and values bubble back up. The client calls get_size() once and receives the total automatically.

Real-World Uses of Composite

DOMAIN                 COMPOSITE EXAMPLE
-------------------------------------------------------
File system            Folder contains files and folders
Organization chart     Manager contains employees and
                        other managers
GUI toolkits           Panel contains buttons, labels,
                        and other panels (React, Qt, Swing)
HTML DOM               
contains

, ,

Menu system Menu contains MenuItems and subMenus Graphics editor GroupShape contains shapes and groups Bill of materials Assembly contains Parts and assemblies

Composite in a UI Component Tree

Window (Composite)
├── Header (Composite)
│   ├── Logo (Leaf)
│   └── NavBar (Composite)
│       ├── NavItem "Home" (Leaf)
│       ├── NavItem "About" (Leaf)
│       └── NavItem "Contact" (Leaf)
├── Body (Composite)
│   ├── Article (Composite)
│   │   ├── Title (Leaf)
│   │   └── Paragraph (Leaf)
│   └── Sidebar (Composite)
│       └── AdBanner (Leaf)
└── Footer (Leaf)

Call window.render() → renders everything recursively.
Call window.getHeight() → sums heights of all children.

Composite vs Simple Collection

SIMPLE COLLECTION (List)          COMPOSITE PATTERN
------------------------------    ---------------------
Holds items of one type.          Holds items that can be
                                  Leaves OR Composites.

No hierarchy.                     Tree hierarchy — depth
                                  can be unlimited.

Client iterates and manages       Client calls one method;
items manually.                   traversal is automatic.

No uniform interface.             All nodes share the same
                                  Component interface.

When to Use the Composite Pattern

Use Composite When:

  • You need to represent part-whole hierarchies (trees).
  • You want clients to treat individual objects and groups identically.
  • The depth and shape of the tree is unknown at design time.

Avoid Composite When:

  • The hierarchy is flat — just a collection with no nesting. A simple list is cleaner.
  • Leaf and Composite objects need very different behavior — the shared interface becomes awkward to maintain.

Advantages and Disadvantages

Advantages

  • Clients work with trees of any complexity through one simple interface.
  • New component types can be added without changing existing client code.
  • Recursive operations (sum, render, find) come naturally from the tree structure.

Disadvantages

  • The shared Component interface can force Leaf classes to implement methods that do not apply to them (like add() or remove()).
  • Enforcing type constraints at the composite level is harder — a Composite can accidentally accept incompatible children.

Quick Summary

COMPOSITE PATTERN — AT A GLANCE

Problem:   You have a tree of objects where individual items
           and groups of items need identical treatment.
Solution:  Make both Leaves and Composites implement the same
           Component interface. Composites forward calls to
           their children recursively.
Key idea:  Clients see no difference between a Leaf and a
           Composite — they call the same methods on both.
Best for:  File systems, UI trees, org charts, DOM, menus,
           graphics editors, bill of materials.

The Composite pattern eliminates the need to treat groups differently from individuals. Build the tree any way you want — the single interface handles everything, no matter how deep or wide the structure grows.

Leave a Comment