Listen to this post
Set up a structure that allows the addition of operations across a variety of classes without changing the classes.
A system that allows for the drawing of primitive vector-based graphical objects (Shapes) might need to allow for various transformational operations to be performed on these shapes, where the nature of the operation would vary based on which shape it is applied to.
- To expand a rectangle, for instance, involves multiplying its corners by a given factor.
- To expand a circle means to increase its radius.
- To rotate a square involves sine and cosine calculations (trigonometry).
- To rotate a circle probably does nothing.
The Visitor would allow for these operations to be extensible. Additional kinds of transformations could be added without having to change the design of the shape objects.
Qualities and principles
The Visitor enables open-closed-ness where the operations are concerned. Each Visitor object is about one set of operations. The visited objects (Shapes, in the example) are also strongly cohesive; they are only responsible for selecting the correct method to call on the Visitor. Clients do not couple to specific Visitors nor to specific visited objects. The accept(Visitor) method they call is established at the abstract level. All Visitors and visited objects are thus interchangeable.
Both the Visitor and the visited objects can be tested by using a Mock of the opposite interface.
- The test of a Visitor would ensure that the operations performed are correct in each case.
- The test of a visited object would ensure it calls the correct method on the Visitor interface.
Questions and concerns
This design allows for the additional of new Visitors very cleanly. It does not allow easy addition of visited objects: the Visitor interface is dependent on the specific types that currently exist. This is not a failure of the pattern; rather, it is simply a reality. In the example, adding a new Shape will require determining how to perform each existing transformation on it.