Visitor
Lets you separate algorithms from the objects on which they operate.
classDiagram
class Visitor {
<<interface>>
+visitConcreteElementA(ConcreteElementA)
+visitConcreteElementB(ConcreteElementB)
}
class ConcreteVisitor1 {
+visitConcreteElementA(ConcreteElementA)
+visitConcreteElementB(ConcreteElementB)
}
class ConcreteVisitor2 {
+visitConcreteElementA(ConcreteElementA)
+visitConcreteElementB(ConcreteElementB)
}
class Element {
<<interface>>
+accept(Visitor)
}
class ConcreteElementA {
+accept(Visitor)
+operationA()
}
class ConcreteElementB {
+accept(Visitor)
+operationB()
}
Visitor <|.. ConcreteVisitor1
Visitor <|.. ConcreteVisitor2
Element <|.. ConcreteElementA
Element <|.. ConcreteElementB
ConcreteElementA ..> Visitor
ConcreteElementB ..> Visitor
When to use
Use the Visitor pattern when you need to perform an operation on all elements of a complex object structure (for example, an object tree). Use when you need to clean up the business logic of auxiliary behaviors.
Explanation
Problem
Imagine that your team develops an app which works with geographic information structured as a colossal graph. Each node of the graph may represent a complex entity such as a city, but also more granular things like industries, sightseeing areas, etc.
You got a task to export the graph into XML. You could add an exportToXML method to each node class. But then you’d have to modify all entity classes. And then someone asks for JSON export. And then SQL export.
Solution
The Visitor pattern suggests that you place the new behavior into a separate class called visitor, instead of trying to integrate it into existing classes. The original object that has to perform the behavior is now passed to one of the visitor’s methods as a parameter, providing the method access to all necessary data contained within the object.
To make this work with different types of nodes, the Visitor interface declares a set of visiting methods, one for each type of node: visitCity, visitIndustry, etc.
The node objects implement an accept(Visitor v) method. They call the appropriate v.visitX(this) method. This double dispatch mechanism allows the proper method to be executed.
Real world problem
- Insurance Agent: An agent (Visitor) visits different types of buildings (House, Factory, Bank). He offers different policies depending on the building type.
- Document Export: Visiting different document nodes (Canvas, Shape, Text) to export them.
Pros and Cons
| Pros | Cons |
|---|---|
| - Open/Closed Principle: You can introduce a new behavior that can work with objects of different classes without changing these classes. - Single Responsibility Principle: You can move multiple versions of the same behavior into the same class. |
- Updates: You need to update all visitors each time a class is added to or removed from the element hierarchy. - Encapsulation: Visitors might lack the necessary access to the private fields and methods of the elements that they’re supposed to work with. |
Comparison
- Command: Visitor executes operation over a collection. Command executes operation over a specific object.
- Composite: Visitors can treat leaves and composites uniformly.
Code example
Typescript
Php