I know what Visitor Pattern is and how to use it; this question is not a duplicate of this one.
I've got a library where I put most of the reusable code I write, and which I link to most of my projects.
Often I need to add features to some classes, but without adding these new features to the library. Let me use a real example:
In this lib I've got a class Shape
, inherited by CircleShape
, PolygonShape
and CompositeShape
.
I'm now developing a graphical application where I need to render these Shape
, but don't want to put a virtual function render
in the core Shape
class, since some of my projects which use Shape
don't do any rendering, and other graphical projects could use different rendering engines (I'm using Qt for this project, but for a game I'd use OpenGL, thus the render
function will need different implementations).
The most famous way to do this is using Visitor Pattern, of course, but this pops a few doubts into my mind:
Any class of any library could need to be extended as my Shape
does. Most of the public libraries (about all of them) don't provide any support for Visitor Pattern; why? why should I?
Visitor Pattern is a way to simulate Double Dispatching in C++. It's not native in C++, and requires to be explicitly implemented, making the class interface more complex: I don't think the applyVisitor
function should be at the same level of my class' functions, I see this like breaking abstraction.
Explicitly up-casting Shape
with dynamic_cast
is more expensive, but to me it looks like a cleaner solution.
So, what should I do? Implementing Double Dispatching in all my library classes? What if the library providing Shape
wasn't mine, but some GPL library found on the internet?
The purpose of a Visitor pattern is to define a new operation without introducing the modifications to an existing object structure. Imagine that we have a composite object which consists of components.
The visitor pattern is used when: Similar operations have to be performed on objects of different types grouped in a structure (a collection or a more complex structure). There are many distinct and unrelated operations needed to be performed.
There are two main participants required to complete the visitor pattern (not including the client code): The elements that have an accept method (by convention we name the method "accept" ) The visitors that define the visit method.
Double dispatch is rarely found in mainstream OOP languages (C# has support for that using dynamic type). One more time, the Visitor pattern is a way to simulate the lack of support for double dispatch. It is another anti-OOP design pattern.
First: "Visitor Pattern is a way to simulate Double Dispatching in C++." This is, erm, not fully right. Actually, double dispatch is one form of multiple dispatch, which is a way to simulate (the missing) multi-methods in C++.
Whether operations on a class hierarchy should be implemented by adding virtual functions or by adding visitors is determined by the probabilities of adding classes vs. adding operations:
Yes, many libraries do not come with a visitor interface.
When we are just looking at the reasoning above, this would be right if the number of classes changes often. That is, if a library is released often, with new classes being added constantly, then providing a visitor interface wouldn't make much sense, because each time a new release brings new classes, everybody using the library need to adapt all of their visitors. So if we only looked at the above reasoning, a visitor interface would seem to only be helpful if the number of classes in a lib's class hierarchy seldom or never changes.
However, with 3rd-party libraries there's another aspect to that: Usually, users cannot change the classes in the library. That is, if they need to add an operation, the only way they can do this is by adding a visitor - if the library provides the hooks for them to plug into it.
So if you are writing a library and feel like users should be able to add operations to it, then you need to provide a way for them to plug their visitors into your lib.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With