Some of you might have already heard of the Visitor Pattern, especially if you have read the GoF book Design Patterns, but do you really use it? Do you use it often?
The common answer to this question is No. Once I was even confrontated with the question “Does anybody use it in real code at all?”.
Well, I do – and here I’m going to explain the why and the how. Actually there are different hows and at the end I will introduce a real elegant how…
Some basics: the Visitor Pattern is used to decouple an operation from the class it operates on and thus allows to create new operations without changing the class.
Let me give you an example: Assume we have a shape class providing the necessary properties to define the shape completely. To draw the shape onto a TCanvas we can introduce a Draw method with a Canvas as parameter. Easy done and easily extended to other shapes. We normally would introduce a TAbstractShape with an abstract Draw method ond override this in the derived classes.
Next task will be to store the shapes somehow into an inifile and read it back. The classical approach would be to introduce two methods LoadFromFile and SaveToFile each with a TCustomInifile parameter probably accompanied by a section name. I’m sure we’ve all done that before.
Requirements change: the drawing should be done with OpenGL and instead of inifiles we use XML now – but the other behaviour has to remain for compatibility reasons. I know, there are OpenGL wrappers that emulate a TCanvas and so are XML wrappers emulating a TCustomInifile, but honestly – such an approach is just crap, isn’t it? We have to introduce some overloaded methods with an OpenGL context for drawing and an XMLDocument for reading and writing to get this done properly. Oh, I just heard someone mentioning Direct3D…
We are actually following a pattern here: introduce an abstract method in the abstract ancestor and implement the specific behaviour in the derived classes. As a side effect we have to use a bunch of units in the abstract class that normally wouldn’t belong there. This can be really awkward when you need the classes, but don’t use the additional functionality, like drawing to OpenGL or writing to XML. Although a perfect valid object-oriented approach, it doesn’t contribute to the modularity of the application.
Here the Visitor Pattern steps in. Its goal is to move the operations from the class (in our case TAbstractShape and descendants) to different visitor classes. So there will be one for drawing to a TCanvas, one for the OpenGL output, two classes for reading and writing inifiles and two for reading and writing XML files.