Patterns: composition · 3 MIN READ
Composite: treat leaves and groups uniformly
Define recursive behavior while guarding the shape of the structure.
Define recursive behavior while guarding the shape of the structure. Composite exposes one operation on both individual values and groups. Trace the worked Go example, then compare the benefit with the cost before applying this design to your own project.
Structural pattern · A MAP OF THE IDEA
- Client calls one operation
- Group delegates to children
- Leaves compute the base result
Useful when
- A tree has meaningful uniform operations
- Clients should not branch on leaf versus group
Watch out
- Cycles and depth need a policy
- Uniform interfaces can expose meaningless leaf operations
Implementation & operation cost: Medium
Fit depends on the task
Editorial suitability, not benchmarks or a universal ranking. Styles describe different axes and can be combined.
The design decision
Composite exposes one operation on both individual values and groups. A file tree can compute size by summing children, while a leaf reports its own size. Decide whether the structure is a true tree; cycles require detection or a different traversal contract.
A complete Go example
Read this program from the entry point and follow the calls shown in the diagram. The output is included at the end so you can check the behavior without a compiler.
package main
import (
"fmt"
)
type Sized interface{ Size() int }
type File int
func (f File) Size() int { return int(f) }
type Folder []Sized
func (f Folder) Size() int {
n := 0
for _, child := range f {
n += child.Size()
}
return n
}
func main() {
root := Folder{File(4), Folder{File(2), File(3)}}
fmt.Println(root.Size())
}
// Output:
// 9
File and Folder satisfy the same Size operation, so the root recursively sums to nine. The interface hides whether a child is a leaf or group. This example assumes an acyclic owned tree and small nonnegative sizes.
Tradeoffs and the simpler alternative
Uniform operations can be elegant, but a group-only mutation API need not be forced onto leaves. Define depth limits or iterative traversal for untrusted trees. Shared nodes and cycles change ownership and may cause duplicate counting or infinite recursion.
TAKE THIS WITH YOU
Gives leaves and groups a common recursive operation. Uniform operations can be elegant, but a group-only mutation API need not be forced onto leaves. Define depth limits or iterative traversal for untrusted trees. Shared nodes and cycles change ownership and may cause duplicate counting or infinite recursion.
Check your understanding
Which statement best describes Composite: treat leaves and groups uniformly?
Go to the source
Progress stays in this browser. No account needed.