Skip to main content

Composite

Overview

Compose objects into tree structures and treat individual objects and composites uniformly.

When to use

  • You need to represent part-whole hierarchies.
  • Clients should handle single items and groups consistently.

Java example

interface Node {
int size();
}

class FileNode implements Node {
private final int bytes;
FileNode(int bytes) { this.bytes = bytes; }
public int size() { return bytes; }
}

class Folder implements Node {
private final List<Node> children = new ArrayList<>();
public void add(Node node) { children.add(node); }
public int size() {
return children.stream().mapToInt(Node::size).sum();
}
}

TypeScript example

interface Node {
size(): number;
}

class FileNode implements Node {
constructor(private bytes: number) {}
size(): number { return this.bytes; }
}

class Folder implements Node {
private children: Node[] = [];
add(node: Node): void { this.children.push(node); }
size(): number { return this.children.reduce((s, n) => s + n.size(), 0); }
}

Pros and cons

Pros:

  • Simplifies client logic for trees.
  • Easy to add new node types.

Cons:

  • Can obscure differences between leaf and composite.

Common pitfalls

  • Exposing mutation when tree should be immutable.
  • Breaking invariants by mixing incompatible nodes.