Visitor pattern
The visitor pattern adds new operations to existing type hierarchies without modifying them, separating algorithms from the objects they operate on via double dispatch.
Visitor Pattern: TL;DR
Visitor separates operations from a stable family of element types. Each element exposes accept(visitor); that method calls the visitor overload for the concrete element, producing double dispatch without putting every operation into the element classes.
Mental model
Think of a document as a set of shapes and a visitor as a tool that walks those shapes. The same document can receive an HTML renderer, a Markdown exporter, or a word counter. The shapes remain focused on their data; each tool owns one operation.
Visitor is a good fit when element types change slowly and operations change often. Its cost is the reverse: adding a new element type requires updating the visitor contract and its implementations.
Problem and Context
You are building a document processing pipeline. You have three element types (Paragraph, Image, Table), and the product team keeps requesting new operations: render to HTML, export to Markdown, count words, extract links, validate accessibility. Every new operation forces you to crack open every element class.
Attempt 1 violates Open/Closed: every new operation reopens every element class. Attempt 2 is fragile: adding a new element type can leave all six operation classes with missing branches unless the design adds an explicit exhaustiveness check. Visitor shifts the trade-off: element classes stay focused and operations become separate visitors, but adding an element type requires updating the visitor contract and its implementations.
Participants and Structure
The double dispatch mechanism is the key insight. When you call element.accept(visitor), the element knows its own type and calls the correct visitor.visitX(this). The visitor then executes the operation specific to that element type. Two virtual calls resolve both the element type and the operation.
In an interview, this is the one diagram you must draw. Sketch two columns (Elements, Visitors) with crossing arrows. The first arrow goes from client to element (accept), the second from element to visitor (visitX). If you can explain double dispatch clearly, you have demonstrated you understand the pattern rather than just memorized its class diagram.
Implementation
The sealed interface (Java 17) is what makes Visitor shine in modern Java. If you add a new element type to the sealed hierarchy, the compiler forces you to add a visit method to every visitor. No silent omissions.
Double Dispatch
Java dispatches methods based on the runtime type of the receiver (single dispatch). Visitor achieves double dispatch: the first dispatch resolves the element type via accept(), the second resolves the visitor type via visitX(). The combination picks the right operation for the right element.
Continue Reading with Premium
Unlock this article and every other in-depth system design guide on the platform with SDEpedia Premium.
Related Articles
Learn how the composite pattern lets you treat individual objects and groups uniformly, building tree structures where clients never distinguish leaves from branches.
The strategy pattern extracts a family of algorithms behind an interface so the client can swap behaviors at runtime without touching the context class.
Learn the five SOLID principles by building a real order-processing system in Java, with before and after code for every principle.