Playing around with the visitor pattern

I have been thinking a little bit about the visitor pattern recently. One of my most recent applications was in combination with a class, which would be used in a message distribution scenario.

The class’ reposibility is – given a list of email addresses – to look up any existing users in my application, and allow the caller to perform an action depending on whether the email belongs to a registered user or not. Pretty simple if you feel like juggling dictionaries and stuff, but I made an even simpler solution.

My email lookup service has the following interface:

And then I have two classes: EmailRecipient and UserRecipient which are both specializations of the abstract superclass Recipient – each containing either an email (a string) or an IUser depending on whether the service was able to look up a user.

Then I have another service, which functions as a message distributor. Given a list of email addresses, either an email or an internal message will be delivered to each recipient. This is a perfect application for the visitor pattern, because it allows us to avoid this kind of brittle code:

I have seen this kind of code in far too many places where inheritance is used. It is obviously very brittle, because what happens if someone adds another kind of Recipient? Nothing at first, because the code will compile like everything is allright. Only after the code is run, and we actually get in a situation where another kind of Recipient is encountered, do we get an error… and in the example above, I was courteous and threw an exception – but what if the original author had not done that? The program could have been silently failing for months before someone found out… yikes!

Another solution is to move the behavior into the specializations – e.g. into an implementation of an abstract SendMessage method on Recipient. But then the specializations would require a reference to either the emailService or the messageService, which would kind of turn the layering upside down, since the domain classes would need to know about some higher level services.

What we really want, is for a service to be able to behave differently depending on which specialization is encountered, and for that service to contain the logic to handle each specialization. And we want errors at compile-time if a specialization is not handled. Enter the visitor pattern…

One way to accomplish this is by using the visitor pattern as described by GoF. It’s pretty simple: Make a call to an abstract method which gets implemented by each specialization, and let that specialization make a suitable callback to identify itself. My visitor interface looks like this:

– and then each specialization must implement the abstract Visit method from the Recipient class:

and then invoke their correponding callback method passing themselves back.

Then my client can create an implementation of IRecipientVisitor, supplying it with the necessary services, allowing the visitor to do different stuff depending on the specializations. But that requires me to implement a class like this every time I have a reason to do different stuff:

Having done this a few times, implementing a new class each time which would be used only once, I started thinking about how to accomplish this with fewer lines of code. One thing that really bugged me, was that I needed to supply the visitor with all kinds of context data to allow the visitor to perform whichever action it would decide to carry out, depending on which Visit(...) method would be called. Then I came up with the generic visitor:

Now my message dispatch can be implemented like this:

Why is this great?

1. I get to implement multiple dispatch with all the safety of the visitor pattern. If I add a new specialization of Recipient, e.g. ErronousEmailRecipient, I add a new method to the IRecipientVisitor interface. That causes the RecipientVisitor to break, so I implement the new method in there as well, in turn causing the code to break everywhere the visitor is used (“break” in a good not introducing bugs-kind-of-way). That way I can be sure that I will know where to handle this new specialization.

2. I get access to the context I am already in. Instead of creating a new visitor and supplying it with sufficient context to carry out whichever actions it needs to perform, I can specify in a short and concise way what I want to do for each specialization, accessing any local variables inside of the scope my labdas are in. That’s just elegant and easy.

3. The code is where it is used. The distance from usage to implementation is zero. Of course, if the implementation is more complex, it may look more like so:

– which is still pretty terse and to-the-point compared to creating an entirely new dedicated class for this.