Composite Pattern vs Visitor Pattern
Two GoF patterns people confuse because they both crawl tree structures. They solve opposite problems. Composite builds the tree; Visitor adds operations to it without touching the classes. Pick by what changes most: the shapes or the operations.
The short answer
Composite Pattern over Visitor Pattern for most cases. Composite is a foundational structural pattern you reach for constantly — any part-whole hierarchy (DOM, file systems, UI trees, ASTs) wants it, and it earns.
- Pick Composite Pattern if have a part-whole hierarchy and want clients to treat leaves and containers uniformly — trees, UI components, file systems, nested menus
- Pick Visitor Pattern if your class hierarchy is STABLE but you keep adding new operations over it (type-check, then optimize, then codegen over the same AST), and you'll accept double-dispatch boilerplate
- Also consider: They compose: build the tree with Composite, then run Visitors across it. That pairing is the legitimate use of Visitor — and the only time most people should touch it.
— Nice Pick, opinionated tool recommendations
They aren't even competing
Half the people Googling this matchup are confused, so let's kill the framing. Composite is structural: it composes objects into trees and lets you treat a single leaf and a whole subtree through one interface. Visitor is behavioral: it bolts a new operation onto an existing object structure without editing those objects' classes. One answers 'how do I model a nested thing,' the other answers 'how do I add the fifteenth operation over that nested thing without touching fifteen classes.' They show up together because Visitor's textbook example IS walking a Composite tree. So the real question isn't 'which pattern' — it's 'which problem do I have.' If you don't have a stable class hierarchy that you're piling operations onto, you don't have a Visitor problem, and reaching for it is cargo-culting. Most codebases have a Composite problem and invent a Visitor problem to feel clever.
Composite: cheap, everywhere, hard to overuse
Composite is one of the highest-leverage patterns in the GoF book because part-whole hierarchies are everywhere: the DOM, React/SwiftUI component trees, filesystem nodes, org charts, nested form fields, scene graphs. The win is uniformity — client code calls render() or size() on a node without branching on 'leaf or container,' and the container just forwards to children. That collapses a pile of conditional tree-walking into clean recursion. The real tradeoff is the leaky interface: do you put add(child) on the common Component interface (transparent — leaves throw on it) or only on Composite (safe — but clients must downcast)? Transparency is the usual pick; you eat a runtime error on a meaningless leaf.add() in exchange for not type-juggling everywhere. That's a fair trade. Composite's failure mode is mild — an awkward interface — not the structural lock-in Visitor inflicts.
Visitor: powerful, and a tax you pay forever
Visitor's pitch is real: separate algorithms from the objects they run on, so adding a new operation is one new class instead of edits to twenty element types. Compilers love it — one AST, many passes (typecheck, optimize, emit). But read the fine print. Visitor solves the expression problem in exactly one direction: operations get cheap, NEW TYPES get brutal. Add one element class and you must touch every visitor interface and every concrete visitor — the opposite of open/closed. It demands double dispatch (accept(visitor) calling visitor.visit(this)), which is ceremony in every language and genuinely ugly in ones without method overloading. It also pressures you to widen element accessors to public so visitors can read state, eroding encapsulation. Choose Visitor only when you are certain the type set is frozen and operations will keep multiplying. Guess wrong and you've welded the worst case into your architecture.
The decision rule
Ask one question: what's volatile — the SHAPES or the OPERATIONS? If you're adding new node types over time (new UI widgets, new file kinds), use Composite and put behavior as methods on the nodes; adding a type is one self-contained class. If the type set is locked and you keep adding cross-cutting operations over it, Visitor earns its boilerplate. In modern languages, weigh the alternatives honestly: sealed types plus pattern matching (Scala, Rust enums, Java switch patterns) give you Visitor's 'add an operation cheaply' benefit with none of the double-dispatch sludge — Visitor is partly a workaround for languages that lacked exhaustive matching. Composite has no such substitute; recursion over a uniform interface is just the right model for trees. So Composite is the default you'll use for a career, and Visitor is the specialist you call in when a compiler-shaped problem actually shows up. Don't summon the specialist for a sapling.
Quick Comparison
| Factor | Composite Pattern | Visitor Pattern |
|---|---|---|
| Problem solved | Model part-whole hierarchies; treat leaf and tree uniformly | Add new operations over a fixed class hierarchy without editing it |
| Breadth of use | Ubiquitous: DOM, UI trees, filesystems, scene graphs | Niche: compilers, ASTs, stable structures with many passes |
| Cost / boilerplate | Low — one interface, forwarding recursion | High — double dispatch, visit-per-type ceremony |
| Adding a new type later | Easy — one new node class, behavior local to it | Brutal — touch every visitor interface and implementation |
| Adding a new operation later | Edit every node class (or pair with Visitor) | Cheap — one new visitor class |
The Verdict
Use Composite Pattern if: You have a part-whole hierarchy and want clients to treat leaves and containers uniformly — trees, UI components, file systems, nested menus.
Use Visitor Pattern if: Your class hierarchy is STABLE but you keep adding new operations over it (type-check, then optimize, then codegen over the same AST), and you'll accept double-dispatch boilerplate.
Consider: They compose: build the tree with Composite, then run Visitors across it. That pairing is the legitimate use of Visitor — and the only time most people should touch it.
Composite Pattern vs Visitor Pattern: FAQ
Is Composite Pattern or Visitor Pattern better?
Composite Pattern is the Nice Pick. Composite is a foundational structural pattern you reach for constantly — any part-whole hierarchy (DOM, file systems, UI trees, ASTs) wants it, and it earns its keep with almost no ceremony. Visitor is a niche, high-cost tool that's correct maybe one time in twenty and miserable the other nineteen. Composite wins because it's broadly useful and cheap; Visitor is narrowly useful and expensive.
When should you use Composite Pattern?
You have a part-whole hierarchy and want clients to treat leaves and containers uniformly — trees, UI components, file systems, nested menus.
When should you use Visitor Pattern?
Your class hierarchy is STABLE but you keep adding new operations over it (type-check, then optimize, then codegen over the same AST), and you'll accept double-dispatch boilerplate.
What's the main difference between Composite Pattern and Visitor Pattern?
Two GoF patterns people confuse because they both crawl tree structures. They solve opposite problems. Composite builds the tree; Visitor adds operations to it without touching the classes. Pick by what changes most: the shapes or the operations.
How do Composite Pattern and Visitor Pattern compare on problem solved?
Composite Pattern: Model part-whole hierarchies; treat leaf and tree uniformly. Visitor Pattern: Add new operations over a fixed class hierarchy without editing it.
Are there alternatives to consider beyond Composite Pattern and Visitor Pattern?
They compose: build the tree with Composite, then run Visitors across it. That pairing is the legitimate use of Visitor — and the only time most people should touch it.
Composite is a foundational structural pattern you reach for constantly — any part-whole hierarchy (DOM, file systems, UI trees, ASTs) wants it, and it earns its keep with almost no ceremony. Visitor is a niche, high-cost tool that's correct maybe one time in twenty and miserable the other nineteen. Composite wins because it's broadly useful and cheap; Visitor is narrowly useful and expensive.
Related Comparisons
Disagree? nice@nicepick.dev