Search code examples
c++visitor-pattern

visitor pattern adding new functionality


I've read thes question about visitor patterns https://softwareengineering.stackexchange.com/questions/132403/should-i-use-friend-classes-in-c-to-allow-access-to-hidden-members. In one of the answers I've read

Visitor give you the ability to add functionality to a class without actually touching the class itself.

But in visited object we have to add either new interface, so we actualy "touch" the class (or at least in some cases to put setters and getters, also changing the class).

How exactly I will add functionality with visitor without changing visiting class?


Solution

  • The visitor pattern indeed assumes that each class interface is general enough, so that, if you would know the actual type of the object, you would be able to perform the operation from outside the class. If this is not the starting point, visitor indeed might not apply.

    (Note that this assumption is relatively weak - e.g., if each data member has a getter, then it is trivially achieved for any const operation.)

    The focus of this pattern is different. If

    1. this is the starting point

    2. you need to support an increasing number of operations

    then what changes to the classs' code do you need to do in order to dispatch new operations applied to pointers (or references) to the base class.

    To make this more concrete, take the classic visitor CAD example:

    Consider the design of a 2D CAD system. At its core there are several types to represent basic geometric shapes like circles, lines and arcs. The entities are ordered into layers, and at the top of the type hierarchy is the drawing, which is simply a list of layers, plus some additional properties.

    A fundamental operation on this type hierarchy is saving the drawing to the system's native file format. At first glance it may seem acceptable to add local save methods to all types in the hierarchy. But then we also want to be able to save drawings to other file formats, and adding more and more methods for saving into lots of different file formats soon clutters the relatively pure geometric data structure we started out with.

    The starting point of the visitor pattern is that, say, a circle, has sufficient getters for its specifics, e.g., its radius. If that's not the case, then, indeed, there's a problem (in fact, it's probably a badly designed CAD code base anyway).

    Starting from this point, though, when considering new operations, e.g., writing to file type A, there are two approaches:

    1. implement a virtual method like write_to_file_type_a for each class and each operation

    2. implement a virtual method accept_visitor for each class only, only once

    The "without actually touching the class itself" in your question means, in point 2 just above, that this is all that's now needed to dispatch future visitors to the correct classes. It doesn't mean that the visitor will start writing getters, for example.