STRUCTURAL PATTERNS / OBJECT DESIGN BRIEF

Composite pattern

The Composite pattern composes objects into tree structures and lets clients treat individual objects (leaves) and groups (composites) uniformly through the same interface.

IntermediatePhase 05 / Topic 3 of 7ResponsibilitiesCollaborationsExtensibility
01

Overview

The Composite pattern composes objects into tree structures and lets clients treat individual objects (leaves) and groups (composites) uniformly through the same interface. A folder and a file both have size(); a folder's size is the sum of its children's sizes, recursively.

Composite is the natural model for any part-whole hierarchy: file systems, UI component trees, organization charts, menus, product bundles, and expression trees. Client code does not need to distinguish leaves from composites, so recursive operations become simple.

Boxes inside boxes

A shipping box can contain products or smaller boxes that contain more products. To find the total weight, you ask each item for its weight; a box answers by asking its contents.

02

When to use it

  • Part-whole hierarchies (trees).
  • Clients should treat single items and groups the same way.
  • Recursive operations: total price, render, count, search.
03

Where it shows up in interviews

Tree structures

Recognize it when: items that can contain other items.

  • Design a file system
  • Design an org chart
  • Design a menu system
Bundles

Recognize it when: products sold alone or as bundles.

  • Design a pricing engine with bundles
  • Design a restaurant combo menu
04

Where it is used in real software

DOM and React trees

Elements contain elements; rendering and event handling recurse through the tree.

Java Swing / AWT

Container extends Component so panels hold buttons and other panels.

File systems

Directories and files share operations like size, permissions, and delete.

05

Key terms

Component
Common interface for leaves and composites.
Leaf
Has no children (File).
Composite
Holds children and delegates to them (Folder).
Recursive composition
Composites can contain composites.
06

How it works, step by step

  1. 1
    Define the component interface

    size(), render(), price().

  2. 2
    Implement leaves

    Return their own value.

  3. 3
    Implement composites

    Hold children, aggregate their results.

  4. 4
    Add child management

    add/remove on composites.

  5. 5
    Guard against cycles

    A folder cannot contain itself.

07

Folder size calculation

root/ { a.txt 10KB, photos/ { p1.jpg 200KB, p2.jpg 300KB }, docs/ { cv.pdf 50KB } }

Step 1 / 4
Nodesize()Computed as
a.txt10Leaf
photos/500200 + 300
docs/5050
root/56010 + 500 + 50

NOWNode: a.txt | size(): 10 | Computed as: Leaf

The client calls root.size() once; recursion handles any depth.

08

Implementation

interface FsNode {  name: string;  size(): number;  print(indent?: string): string[];} class FileNode implements FsNode {  constructor(readonly name: string, private bytes: number) {}  size() { return this.bytes; }  print(indent = "") { return [`${indent}${this.name} (${this.bytes})`]; }} class Folder implements FsNode {  private children: FsNode[] = [];  constructor(readonly name: string) {}  add(node: FsNode) {    if (node === this) throw new Error("A folder cannot contain itself");    this.children.push(node);    return this;  }  size() { return this.children.reduce((s, c) => s + c.size(), 0); }  print(indent = ""): string[] {    return [`${indent}${this.name}/ (${this.size()})`, ...this.children.flatMap((c) => c.print(indent + "  "))];  }} const root = new Folder("root")  .add(new FileNode("a.txt", 10))  .add(new Folder("photos").add(new FileNode("p1.jpg", 200)).add(new FileNode("p2.jpg", 300)));root.size(); // 510
09

Complexity and performance

Aggregate operationO(n) nodes

Visits each once.

Recursion depthO(tree height)

Beware very deep trees.

10

Trade-offs

Uniformity vs type safety

Putting add() on the common interface makes leaves implement meaningless methods; putting it only on composites requires type checks when building.

Caching aggregates

Recomputing sizes on every call is simple; caching needs invalidation when children change.

11

Variants and related techniques

Composite + Visitor

Add operations over the tree without changing node classes.

Composite + Iterator

Traverse the tree depth-first or breadth-first.

12

Common mistakes

  • Cycles in the tree.

    Fix: Validate on add or track parents.

  • Clients checking instanceof Folder everywhere.

    Fix: Move behavior into the component interface.

13

Interview questions

How would you design a file system?

Composite: an abstract FsNode with name, size, and permissions; File as a leaf; Directory as a composite holding children; operations like size and search recurse through the tree.

Where do you put add/remove child methods?

Usually only on the composite for type safety; the transparent alternative puts them on the interface with leaves throwing, which is more uniform but violates LSP.

14

Practice problems

ProblemDifficultyWhat it trains
File system with size and findEasyRecursion.
Org chart with total salary per managerMediumAggregates.