This is the 21st post in a series on design patterns.
Visitor is a behavioral design pattern that lets you separate algorithms from the objects on which they operate.
Suppose you have a canvas that consists of various geometric shapes. You need to export the canvas into XML format now. Your plan was to add an export method to each geometric shape class and then iterate through each shape on the canvas, executing the export method.
Does it make sense to have the XML export code in the shape classes? These classes were primarily responsible for displaying coordinates on canvas and working with coordinates.
In addition, it was highly likely that someone would ask for the ability to export in another format after the feature was implemented.
Visitor Design Pattern
The Visitor pattern suggests that you place the new behavior into a separate class called visitor rather than trying to integrate it into existing classes. Now, the original object that had to perform this behavior is passed as an argument to the visitor’s method, giving that method access to all the data contained within the object.
UML Class Diagram
Not familiar with UML Class Diagram? I have written a detailed post on the UML Class diagram.
- The visitor interface should be declared with a set of visiting methods, one for each concrete element class in the program.
- Declare the element interface with the acceptance method to accept the visitor object as an argument.
- Implement the acceptance method in all concrete element classes. It must simply redirect the call to a visiting method on the incoming visitor object matching the class of the current element.
- Visitors should only interact with the Element classes through the visitor interface. However, visitors must be aware of all concrete element classes that are referenced as parameter types of the visiting methods.
- Whenever a behavior cannot be implemented within an element hierarchy, create a new concrete visitor class and implement all of the visitor methods.
- Clients must create visitor objects and pass them to elements via the acceptance methods.
Source Code Implementation
The Visitor interface defines visiting methods that can take concrete elements of an object structure as arguments.
Concrete Visitor XMLExportVisitor implements several versions of the same behavior, tailored for different concrete element classes.
The Shape (Element) interface declares a method to accept visitors. It should have one parameter declaring the type of the visitor interface.
Concrete Shapes Dot, Rectangle & Circle must each implement the acceptance method. This method redirects the call to the proper visitor’s method corresponding to the current element class.
Typically, the Client represents a collection or some other complex object. In most cases, clients are unaware of all the concrete element classes because they work with objects from that collection via some abstract interface.
Drawing Dot at (10,20)
Drawing Rectangle at (100,0)
Drawing Circle at (234,20)
Exporting Dot ID and coordinates: ID: 63741, x:10, y:20
Exporting Dot ID and coordinates: ID: 29577, x:100, y:0
Exporting Dot ID and coordinates: ID: 2254, x:234, y:20
When To Apply Visitor Design Pattern
- You should use the Visitor pattern when you need to operate on all elements of a complex object structure.
- You can use the Visitor pattern to clean up the auxiliary behavior business logic. You can make the primary classes of your app more focused on their main tasks by extracting all other behaviors into visitor classes.
- The pattern is useful when a behavior makes sense in only some classes of a class hierarchy, but not in others.
Pros of Visitor Design Pattern
- By introducing a new behavior, you can work with objects of different classes without having to change these classes.
- Multiple versions of the same behavior can be put in the same class.
- As a visitor object interacts with various objects, it can accumulate some useful information. It can be handy when you want to traverse some complex object structure, such as an object tree, and apply the visitor to each object in the structure.