Composite
Composite is a structural pattern that lets individual objects and groups of objects be treated through the same interface. It builds a tree structure while allowing the client to call the same method without caring whether the target is a leaf node or a group.
βΆArchitecture Diagram
π StructureDashed line animations indicate the flow direction of data or requests
How do you calculate the total size of a folder? Inside a folder there can be files, and there can be subfolders. Inside subfolders there can be more folders still. If the client has to check 'is this a file or a folder?' every time and branch accordingly, the code is littered with type checks and conditionals. Every new node type forces updates to every branch. As tree depth grows, this complexity scales exponentially.
This problem shows up immediately in UI and document systems that naturally form trees. One screen element may be a terminal node like a button, while another may be a container like a panel holding many child elements. If rendering or event-handling code has to ask 'is this a single widget or a container?' every time, both the branching and the recursive logic grow with every new widget type. Composite comes from that pressure. Parts and wholes share the same interface, and containers simply forward the same request recursively to their children. What started in early GUI libraries keeps reappearing today in React component trees, the DOM tree, and file-system APIs.
Composite's structure resembles Russian nesting dolls (matryoshka). A large doll contains a smaller doll, which contains an even smaller one. But unlike matryoshka, from the outside every doll looks the same regardless of size.
Three roles make up the structure. The Component interface defines the shared contract for all nodes. A Leaf is a terminal object with no children that performs the actual work. A Composite holds a list of child Components and, when its operation() is called, recursively delegates the same operation() to every child.
For example, calling getSize() on a folder causes the folder to call getSize() on each child file and subfolder and sum the results. Subfolders repeat the same process. The client makes a single request at the top, and the entire tree handles itself.
Composite and Decorator are frequently compared because both use recursive composition. The difference lies in purpose. Composite is for grouping multiple objects and treating them as one; Decorator is for layering functionality onto a single object. A Composite's tree can have many children, while a Decorator always wraps exactly one target. Iterator is also related. Composite builds the tree structure; Iterator separates the method of traversing that structure. Building the structure is Composite's role; deciding the traversal strategy is Iterator's. Determining whether you need a tree structure or just need to separate traversal is the first question that distinguishes the two.
Composite appears almost anywhere data or UI naturally takes tree form. Using the same interface to copy, move, and delete files and folders in a file explorer; nesting React components within components and applying the same lifecycle; moving and resizing shape groups just like individual shapes in a graphics editor -- all are Composite. The signal for adoption is clear: when code that branches on 'is this a single object or a group?' is repeated in multiple places, or when you need to apply the same operation uniformly across a tree of nodes. However, applying Composite to every hierarchy intentionally hides the difference between Leaf and Composite, which can bloat the interface with operations that are meaningful only to one type. First determine whether a tree structure is actually needed or whether a simple list would suffice.