The Visitor is a behavioral design pattern. It allows the designer to define new operations on an object structure and its elements, without modifying the object structure itself.
You should use the Visitor pattern when:
- An object structure contains many classes with different interfaces that you want to perform operations on depending on the concrete class of the objects.
- Many unrelated operations need to be performed on the parts of an object structure and you don't want to pollute the classes' interface by adding these operations. Visitor allows you to gather these operations in a separate class instead.
- The classes defining the object structure rarely change but you expect to frequently add new operations to be performed on them.
The Visitor describes the relations between three distinct classes:
- ObjectStructure - Provides a visitor with access to its elements
- Element - Accepts visits.
- Visitor - Accesses an element to perform operations.
Figure 1 graphically describes these Visitor pattern relationships.
The Visitor pattern uses Double dispatch to reduce the coupling between the visitor and the object structure.
The Visitor pattern allows a visitor object to access and perform operations on an element object. A summary of the Visitor pattern communications is given in Fig. 2. Here the following interactions are shown:
- Sequence 1 - The object aVisitor1 performs an operation on anElementA
- Sequence 2 - The object aVisitor2 performs an operation on anElementA
- Sequence 3 - The object aVisitor1 performs an operation on anElementB
- Sequence 4 - The object aVisitor2 performs an operation on anElementB
- Adding new operations is easy. Just add a new Visitor class
- Separates unrelated behaviours and gathers related ones
- Visit across more than one class hierarchy
- Adding a new ConcreteElement is difficult
- Elements may expose otherwise private attributes
You can find here a nicely explained java code example of the Visitor Pattern usage in the real world.
The Acyclic Dependencies Principle
The Visitor pattern conflicts with the Acyclic dependencies principle. Here, the concrete visitor depends on the interface of the concrete elements it visits. Similarly, the concrete elements must be familiar with interface of all visiting concrete visitors.
- Where a visitor pattern is necessary, the ill effects of cyclic dependency can be mitigated by ensuring that cyclically dependent classes are deployed within the same package.
- Bob Martin suggests a solution to this problem in his paper Acyclic Visitor. This solution uses casting to move the dependency from the interface of the concrete elements to the implementation. The abstract element is designed to depend on the abstract visitor, within a concrete element's implementation, down-casting is used to extract and consume the concrete visitor's interface.
The Visitor pattern deliberately violates Riel's heuristic Keep related data and behavior in one place by separating the desired behaviour from the data on which it operates. This means that getters and setters will need to be added to the object structure to allow the visitor to get at the data it needs. This is usually a sign that related data and behaviour is not kept in one place. Adding getters and setters to the object structure also violates related heuristics such as the Law of Demeter and Tell, don't ask. In addition, it compromises the encapsulation of data in the object structure, allowing access to this data not just from the visitor but from other parts of the system.
The Visitor design pattern can lead to tight coupling between the visitor and the object structure. This happens because the behaviour has been separated from the data.
- Composite: Visitors can be useful to perform operations over a composite object structure.
- Interpreter: Visitors can be used to do the interpretation.
- Keep related data and behavior in one place
- Behavioral completeness
- Feature envy smell
- Tell, don't ask
Creational: Abstract Factory | Builder | Factory Method | Prototype | Singleton