Visitor Pattern
In the Visitor Pattern, we use a visitor class which changes the executing algorithm of an element class. By this way, the execution algorithm of element can evolve as the visitor changes. This type of design pattern is a behavioral design pattern. According to the pattern, the element object has to accept the visitor object so that the visitor object can do the operations on the element object.
Intent
It is used to separate the data structure from the operations performed on it, making it easier to add new operations without modifying the data structure itself.
Problem It Solves
- It addresses the coupling between a stable data structure and volatile operations, allowing operations to change independently of the data structure.
Use Cases
- When you need to perform multiple different and unrelated operations on objects in an object structure, especially when these operations need to avoid "polluting" the object classes themselves.
Implementation
- Define the Visitor Interface: Declares a series of visit methods, one for each element class in the data structure.
- Create Concrete Visitors: Implement the visitor interface, providing concrete implementations for each visit method.
- Define the Element Interface: Declares a method to accept a visitor.
- Create Concrete Elements: Implement the element interface. Each concrete element class corresponds to a specific object in the data structure.
Key Code
- Visitor Interface: Contains methods to visit different elements.
- Concrete Visitor: Implements the visitor interface, containing the visit logic for each element class.
- Element Interface: Contains a method to accept a visitor.
- Concrete Element: Implements the element interface, providing an entry point for the visitor to access.
Application Example
- Visiting Scenario: A visitor (e.g., you) visits a friend's house. The friend, as the element, provides information, and the visitor makes judgments based on that information.
Advantages
- Single Responsibility Principle: The Visitor Pattern adheres to the Single Responsibility Principle, where each class has only one responsibility.
- Extensibility: It is easy to add new operations to the data structure.
- Flexibility: Visitors can be independent of changes in the data structure.
Disadvantages
- Violates the Law of Demeter: Elements need to expose their internal information to visitors.
- Element Classes Are Hard to Change: Element classes need to maintain compatibility with visitors.
- Depends on Concrete Classes: The Visitor Pattern depends on concrete classes rather than interfaces, violating the Dependency Inversion Principle.
Usage Suggestions
- Consider using the Visitor Pattern when the object structure is stable but requires multiple new operations to be defined on it.
- Use the Visitor Pattern to encapsulate operations when you need to avoid "polluting" the object classes.
Notes
- The Visitor Pattern can be used for functional unification, such as report generation, user interface display, interceptors, and filters.
Main Roles Involved
- Visitor:
- Defines the interface for visiting elements.
- Concrete Visitor:
- Implements the visitor interface, providing access and corresponding operations for each concrete element class.
- Element:
- Defines a method to accept a visitor.
- Concrete Element:
- Implements the element interface, providing an
acceptmethod that allows the visitor to access and operate.
- Implements the element interface, providing an
- Object Structure (Optional):
- Defines how to assemble concrete elements, such as a composite class.
- Client (Optional):
- Uses the Visitor Pattern to operate on the object structure.
We will create a ComputerPart interface defining the accept operation. Keyboard, Mouse, Monitor, and Computer are entity classes implementing the ComputerPart interface. We will define another interface ComputerPartVisitor, which defines the visitor class operations. Computer uses the entity visitor to perform the corresponding actions.
VisitorPatternDemo, our demo class uses Computer and ComputerPartVisitor classes to demonstrate the usage of the Visitor Pattern.
Step 1
Define an interface representing an element.
ComputerPart.java
public interface ComputerPart {
public void accept(ComputerPartVisitor computerPartVisitor);
}
Step 2
Create entity classes that extend the above class.
Keyboard.java
public class Keyboard implements ComputerPart {
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}
Monitor.java
public class Monitor implements ComputerPart {
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}
Mouse.java
public class Mouse implements ComputerPart {
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}
Computer.java
public class Computer implements ComputerPart {
ComputerPart[] parts;
public Computer() {
parts = new ComputerPart[]{new Mouse(), new Keyboard(), new Monitor()};
}
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
for (int i = 0; i < parts.length; i++) {
parts.accept(computerPartVisitor);
}
computerPartVisitor.visit(this);
}
}
Step 3
Define an interface representing a visitor.
ComputerPartVisitor.java
public interface ComputerPartVisitor {
public void visit(Computer computer);
public void visit(Mouse mouse);
public void visit(Keyboard keyboard);
public void visit(Monitor monitor);
}
Step 4
Create entity visitors that implement the above class.
ComputerPartDisplayVisitor.java
public class ComputerPartDisplayVisitor implements ComputerPartVisitor {
@Override
public void visit(Computer computer) {
System.out.println("Displaying Computer.");
}
@Override
public void visit(Mouse mouse) {
System.out.println("Displaying Mouse.");
}
@Override
public void visit(Keyboard keyboard) {
System.out.println("Displaying Keyboard.");
}
@Override
public void visit(Monitor monitor) {
System.out.println("Displaying Monitor.");
}
}
Step 5
Use ComputerPartDisplayVisitor to display the components of Computer.
VisitorPatternDemo.java
public class VisitorPatternDemo {
public static void main(String[] args) {
ComputerPart computer = new Computer();
computer.accept(new ComputerPartDisplayVisitor());
}
}
Step 6
Execute the program, and the output will be:
Displaying Mouse.
Displaying Keyboard.
Displaying Monitor.
Displaying Computer.
YouTip