What classes are involved in Visitor?
Implementing the Visitor pattern involves five main roles (classes), that separate the structure of objects from the operations performed on them.
1. Element
An interface or abstract class that accepts a visitor. Every element of the structure must be able to "let" a visitor in, so it can perform the needed action.
Main method:
void accept(Visitor visitor);Task:
- declare an
accept()method that takes aVisitorobject; - delegate handling to it by calling
visitor.visit(this).
Example:
interface Shape {
void accept(ShapeVisitor visitor);
}2. ConcreteElement
The real classes that make up the data structure (nodes, files, shapes, and so on).
Each implements the accept() method and calls the visitor's corresponding visit() method,
passing itself as an argument.
Task:
- define how to "invite" a visitor;
- hold the data the visitor will work on.
Example:
class Circle implements Shape {
public void accept(ShapeVisitor visitor) {
visitor.visit(this); // double dispatch
}
}
class Square implements Shape {
public void accept(ShapeVisitor visitor) {
visitor.visit(this);
}
}3. Visitor
An interface that defines a set of visit() methods
for each type of element that can be visited.
Task:
- declare separate methods for handling each specific element type;
- provide "external" operations on objects without changing their classes.
Example:
interface ShapeVisitor {
void visit(Circle circle);
void visit(Square square);
}4. ConcreteVisitor
An implementation of the Visitor interface that describes a specific operation
performed on each type of element.
Task:
- implement all the
visit()methods; - define specific behavior (export, counting, validation, and so on).
Example:
class AreaVisitor implements ShapeVisitor {
public void visit(Circle circle) {
System.out.println("Calculating the circle's area");
}
public void visit(Square square) {
System.out.println("Calculating the square's area");
}
}5. ObjectStructure
The component that stores and manages the collection of elements.
It can provide iteration and call accept() for each element
so that the visitor processes the whole structure.
Task:
- aggregate the elements;
- provide traversal of the whole structure.
Example:
class Drawing {
private List<Shape> shapes = new ArrayList<>();
public void addShape(Shape shape) { shapes.add(shape); }
public void apply(ShapeVisitor visitor) {
for (Shape shape : shapes) {
shape.accept(visitor);
}
}
}6. The Overall Interaction Structure
+-------------------+
| Visitor |
|-------------------|
| + visit(Circle) |
| + visit(Square) |
+---------^---------+
|
+-----------+-----------+
| ConcreteVisitor |
| (for example: AreaVisitor) |
+------------------------+
(calls)
↑
+--------------------------------+
| Element |
|--------------------------------|
| + accept(Visitor visitor) |
+-----------------^---------------+
|
+-----------+-----------+
| ConcreteElement |
| (Circle, Square, etc.)|
+-----------------------+
↑
+------------------+
| ObjectStructure |
|------------------|
| + apply(visitor) |
+------------------+Conclusion
| Class | Role |
|---|---|
| Element | Defines the interface for "accepting" a visitor |
| ConcreteElement | Implements accept() and calls visit(this) |
| Visitor | Defines the interface for all operations on elements |
| ConcreteVisitor | Implements specific actions for each type |
| ObjectStructure | Manages the collection of elements and lets the visitor traverse them |
Summary:
In Visitor, the logic of actions is moved into separate classes (visitors), while the structure's elements only provide an "entry point",
accept(). This lets you add new operations without changing the elements.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.