What is the Visitor pattern used for?
The Visitor pattern is used when you need to perform different operations on objects of a complex structure, but without changing the classes of those objects.
It lets you move behavior (operations) outside the class hierarchy, and add new actions without changing the structure's elements themselves.
1. The Main Idea
Separate the data structure from the behavior applied to it.
The structure stays unchanged, and new operations are added through "visitors" that traverse the elements and perform the needed action on them.
2. Participants in the Pattern
| Role | Description |
|---|---|
| Visitor | An interface defining a set of operations for different types of elements |
| ConcreteVisitor | Specific implementations of actions (for example, export, counting, validation) |
| Element | The interface that accepts a visitor (accept(Visitor v)) |
| ConcreteElement | The real structure elements that "accept" a visitor |
| ObjectStructure | A collection of elements that a visitor can traverse |
3. Example (Java)
Let's say we have a structure of documents of different types, and we want to perform different operations on them (for example, counting characters, exporting to PDF, and so on), but we don't want to change their code every time.
Interfaces
interface DocumentVisitor {
void visit(TextDocument doc);
void visit(ImageDocument doc);
}
interface DocumentElement {
void accept(DocumentVisitor visitor);
}Elements
class TextDocument implements DocumentElement {
String text = "Hello Visitor!";
public void accept(DocumentVisitor visitor) {
visitor.visit(this);
}
}
class ImageDocument implements DocumentElement {
String name = "image.png";
public void accept(DocumentVisitor visitor) {
visitor.visit(this);
}
}Concrete Visitors
class WordCountVisitor implements DocumentVisitor {
public void visit(TextDocument doc) {
System.out.println("Words: " + doc.text.split(" ").length);
}
public void visit(ImageDocument doc) {
System.out.println("Word count doesn't apply to an image");
}
}
class ExportVisitor implements DocumentVisitor {
public void visit(TextDocument doc) {
System.out.println("Exporting text to PDF: " + doc.text);
}
public void visit(ImageDocument doc) {
System.out.println("Exporting image to PDF: " + doc.name);
}
}Usage
List<DocumentElement> docs = List.of(new TextDocument(), new ImageDocument());
DocumentVisitor visitor = new ExportVisitor();
for (DocumentElement d : docs) {
d.accept(visitor);
}4. What This Gives You
- The elements (the data structure) don't change, while visitors implement different processing scenarios.
- New actions can easily be added by simply creating a new
Visitor. - Double dispatch is supported: behavior depends on both the visitor's type and the element's type.
5. Advantages
Adding new operations without changing the element classes. Centralizing the handling logic for each type. Separating data and actions, the code becomes cleaner.
6. Disadvantages
- Adding new element types requires changing every visitor.
- The number of classes increases.
- Uses double dispatch, which complicates the architecture.
7. When to Use It
- When you need to add new operations often, while the data structure rarely changes.
- When objects of different classes need to be processed in a unified way.
- Example: AST parsers, compilers, data export, reporting systems.
Conclusion
The Visitor pattern is used to:
- separate the structure from the operations performed on it,
- add new actions without changing the element classes,
- provide traversal and processing of different object types through unified logic.
Summary:
Visitor is a "guest" that comes into the objects, does the needed action with them, but doesn't change them from the inside.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.