I keep seeing references to the visitor pattern in blogs but I've got to admit, I just don't get it. I read the wikipedia article for the pattern and I understand its mechanics but I'm still confused as to when I'd use it.
As someone who just recently really got the decorator pattern and is now seeing uses for it absolutely everywhere I'd like to be able to really understand intuitively this seemingly handy pattern as well.
The reason for your confusion is probably that the Visitor is a fatal misnomer. Many (prominent1!) programmers have stumbled over this problem. What it actually does is implement double dispatching in languages that don't support it natively (most of them don't).
1) My favourite example is Scott Meyers, acclaimed author of “Effective C++”, who called this one of his most important C++ aha! moments ever.
I found it easier in following links:
In http://www.remondo.net/visitor-pattern-example-csharp/ I found an example that shows an mock example that shows what is benefit of visitor pattern. Here you have different container classes for
Pill
:As you see in above, You
BilsterPack
contain pairs of Pills' so you need to multiply number of pair's by 2. Also you may notice thatBottle
useunit
which is different datatype and need to be cast.So in main method you may calculate pill count using following code:
Notice that above code violate
Single Responsibility Principle
. That means you must change main method code if you add new type of container. Also making switch longer is bad practice.So by introducing following code:
You moved responsibility of counting number of
Pill
s to class calledPillCountVisitor
(And we removed switch case statement). That mean's whenever you need to add new type of pill container you should change onlyPillCountVisitor
class. Also noticeIVisitor
interface is general for using in another scenarios.By adding Accept method to pill container class:
we allow visitor to visit pill container classes.
At the end we calculate pill count using following code:
That mean's: Every pill container allow the
PillCountVisitor
visitor to see their pills count. He know how to count your pill's.At the
visitor.Count
has the value of pills.In http://butunclebob.com/ArticleS.UncleBob.IuseVisitor you see real scenario in which you can not use polymorphism (the answer) to follow Single Responsibility Principle. In fact in:
the
reportQtdHoursAndPay
method is for reporting and representation and this violate the Single Responsibility Principle. So it is better to use visitor pattern to overcome the problem.Quick description of the visitor pattern. The classes that require modification must all implement the 'accept' method. Clients call this accept method to perform some new action on that family of classes thereby extending their functionality. Clients are able to use this one accept method to perform a wide range of new actions by passing in a different visitor class for each specific action. A visitor class contains multiple overridden visit methods defining how to achieve that same specific action for every class within the family. These visit methods get passed an instance on which to work.
When you might consider using it
As Konrad Rudolph already pointed out, it is suitable for cases where we need double dispatch
Here is an example to show a situation where we need double dispatch & how visitor helps us in doing so.
Example :
Lets say I have 3 types of mobile devices - iPhone, Android, Windows Mobile.
All these three devices have a Bluetooth radio installed in them.
Lets assume that the blue tooth radio can be from 2 separate OEMs – Intel & Broadcom.
Just to make the example relevant for our discussion, lets also assume that the APIs exposes by Intel radio are different from the ones exposed by Broadcom radio.
This is how my classes look –
Now, I would like to introduce an operation – Switching On the Bluetooth on mobile device.
Its function signature should like something like this –
So depending upon Right type of device and Depending upon right type of Bluetooth radio, it can be switched on by calling appropriate steps or algorithm.
In principal, it becomes a 3 x 2 matrix, where-in I’m trying to vector the right operation depending upon the right type of objects involved.
A polymorphic behaviour depending upon the type of both the arguments.
Now, Visitor pattern can be applied to this problem. Inspiration comes from the Wikipedia page stating – “In essence, the visitor allows one to add new virtual functions to a family of classes without modifying the classes themselves; instead, one creates a visitor class that implements all of the appropriate specializations of the virtual function. The visitor takes the instance reference as input, and implements the goal through double dispatch.”
Double dispatch is a necessity here due to the 3x2 matrix
Here is how the set up will look like -
I wrote the example to answer another question, the code & its explanation is mentioned here.
Cay Horstmann has a great example of where to apply Visitor in his OO Design and patterns book. He summarizes the problem:
The reason it's not easy is because operations are added within the structure classes themselves. For example, imagine you have a File System:
Here are some operations (functionalities) we might want to implement with this structure:
You could add functions to each class in the FileSystem to implement the operations (and people have done this in the past as it's very obvious how to do it). The problem is that whenever you add a new functionality (the "etc." line above), you might need to add more and more methods to the structure classes. At some point, after some number of operations you've added to your software, the methods in those classes don't make sense anymore in terms of the classes' functional cohesion. For example, you have a
FileNode
that has a methodcalculateFileColorForFunctionABC()
in order to implement the latest visualization functionality on the file system.The Visitor Pattern (like many design patterns) was born from the pain and suffering of developers who knew there was a better way to allow their code to change without requiring a lot of changes everywhere and also respecting good design principles (high cohesion, low coupling). It's my opinion that it's hard to understand the usefulness of a lot of patterns until you've felt that pain. Explaining the pain (like we attempt to do above with the "etc." functionalities that get added) takes up space in the explanation and is a distraction. Understanding patterns is hard for this reason.
Visitor allows us to decouple the functionalities on the data structure (e.g.,
FileSystemNodes
) from the data structures themselves. The pattern allows the design to respect cohesion -- data structure classes are simpler (they have fewer methods) and also the functionalities are encapsulated intoVisitor
implementations. This is done via double-dispatching (which is the complicated part of the pattern): usingaccept()
methods in the structure classes andvisitX()
methods in the Visitor (the functionality) classes:This structure allows us to add new functionalities that work on the structure as concrete Visitors (without changing the structure classes).
For example, a
PrintNameVisitor
that implements the directory listing functionality, and aPrintSizeVisitor
that implements the version with the size. We could imagine one day having an 'ExportXMLVisitor` that generates the data in XML, or another visitor that generates it in JSON, etc. We could even have a visitor that displays my directory tree using a graphical language such as DOT, to be visualized with another program.As a final note: The complexity of Visitor with its double-dispatch means it is harder to understand, to code and to debug. In short, it has a high geek factor and goes agains the KISS principle. In a survey done by researchers, Visitor was shown to be a controversial pattern (there wasn't a consensus about its usefulness). Some experiments even showed it didn't make code easier to maintain.
Everyone here is correct, but I think it fails to address the "when". First, from Design Patterns:
Now, let's think of a simple class hierarchy. I have classes 1, 2, 3 and 4 and methods A, B, C and D. Lay them out like in a spreadsheet: the classes are lines and the methods are columns.
Now, Object Oriented design presumes you are more likely to grow new classes than new methods, so adding more lines, so to speak, is easier. You just add a new class, specify what's different in that class, and inherits the rest.
Sometimes, though, the classes are relatively static, but you need to add more methods frequently -- adding columns. The standard way in an OO design would be to add such methods to all classes, which can be costly. The Visitor pattern makes this easy.
By the way, this is the problem that Scala's pattern matches intends to solve.