what is visitor pattern
A pattern that separates the algorithm from the object structure, which is the data for the algorithm. Using the visitor pattern, we can add a new operation to the class hierarchy without modifying the classes themselves.
Different, more technical way to describe the visitor pattern is to say that it implements double dispatch. Let’s explain the term.
The regular virtual function calls, if we invoke the b->f()
virtual function through a pointer to the base class, the call is dispatched to D1::f()
or D2::f()
, depending on the real type of the object. This is the single dispatch. Now let’s assume that the function f()
also take an argument that is the pointer to a base class:
This would be double dispatch.
why we need visitor pattern
Why would we want to add an operation externally instaed of implementing it in every class in herarchy class-tree? Consider the example of the serialization/deserialization problem.
For example, we may need to write an object into a memory buffer, to be transmitted across the network and decerialized on another machine. Alternatively, we may need to save the object to disk, or else we may need to convert all objects in a container to a markup format such as JSON.
- The straighforward approach would have us add a serialization and a deserialization method to every object for every serialization machanism. If a new and different serialization approach is needed, we have to go over the entire class hierarchy and add support for it.
- An alternative is to implement the entire serialization/deserialization operation in a separate function that can handle all classes. The resulting code is a loop that iterates over all objects, with a large decision tree inside of it. The code must interrogate every object and determine its type, for example, using dynamic casts. When a new class is added to the hierarchy, all serialization and deserialization implementations must be updated to handle the new objects.
Both are difficult to maintain for large hierarchies. The visitor pattern offers a solution.
visitor pattern
Now we want to add some operations to ousr classes, such as “feed the pet” or “play with the pet”
We need to make the Pet
hierarchy visitable, which means we do need to modify it, but only once, regradless of how many operations we want to add later.
Now out Pet
hierarchy is visitable, and we have an abstract PetVisitor
class. Everything is ready to implement new operations for our classes.
The call accept()
ends up dispatched to a particular visit()
function based on two factors - the type of the visitable *p
object and the type of the *v
visitor. Stress the aspect of the visitor pattern, we can write code like this:
visit complex objects
The correct way to handle the component objects is to simply visit each one, and thus delegate the problem to someone else.