Card 01/ 08

ConceptDifficulty: Intermediate3 min

Composite Pattern: Treating a Group and a Single Item the Same Way

Ask a folder for its size, and it asks each file and folder inside it.

The Composite pattern gives a single item and a group of items one shared interface, so that code using them never asks which it holds. The group, called the composite, answers each call by passing it to its children and combining their answers, and because a composite is itself an item, groups can hold groups to any depth. This card covers the problem, the intent, and when the pattern fits.

The problem appears wherever data forms a tree, also called a part-whole hierarchy: files and folders, products and bundles, people and departments, shapes and groups of shapes. Without the pattern, each piece of code that walks the tree checks the type of every node and branches on it.

Branching on the type, and one call for every node

Without the patternthe caller checks every node

py
def size(node):
    if isinstance(node, File):
        return node.size_kb
    total = 0
    for child in node.children:
        total += size(child)
    return total

Every function that walks the tree repeats the check, and a new kind of node means editing each one.

With the patterneach node answers for itself

py
class Folder(Node):
    def size(self):
        return sum(child.size() for child in self._children)


total = root.size()

A file returns its own size, a folder sums its children, and the caller makes one call.

The Gang of Four state the intent as: compose objects into tree structures to represent part-whole hierarchies, so that clients treat individual objects and compositions of objects uniformly. The recursion lives in the composite, written once, instead of in every caller.

Composite is one of seven structural patterns, the family that composes classes and objects into larger structures.

The structural family, with this pattern marked
PatternWhat it does
AdapterGives an existing object the interface a client expects.
BridgeSeparates an abstraction from its implementation so both can vary.
Composite (this topic)Treats a tree of objects and a single object the same way.
DecoratorAdds behaviour by wrapping an object in another with the same interface.
FacadePuts one simple interface in front of a complex subsystem.
FlyweightShares the common part of many small objects to save memory.
ProxyStands in for an object to control access to it.

Composite and Decorator share a shape: both are built by recursive composition, an object holding objects of its own interface. A decorator holds exactly one and adds behaviour to it; a composite holds any number and combines what they return.

Composite

Use it when

  • The data is a tree, and the same question is asked of single items and of groups.
  • Callers should not need to know how deep the tree is or what kind of node they hold.
  • New kinds of node will be added, and the walking code should not change when they are.

Avoid it when

  • The structure is flat, a list with no groups inside it, where a loop is enough.
  • Single items and groups support very different operations, so a shared interface would be mostly refusals.
  • The tree can contain cycles, where the recursion would never end without extra checks.

← → move through sections and cards