Live patterns: Switching to the visitor design pattern

For more than a two years now, I’ve been working on the WorldMate Live application. In its essence, it is built around the concept of managing itineraries, and on top of that, it provides plenty of services. The entire system consists of mobile applications, currently BlackBerry and SmartPhones, an Outlook add-in and my team’s part – the web application and the back end services. This intro came so I can describe one of my favourite design decisions we made early during the development, which proved to be very successful over time, and this is the usage of the Visitor design pattern. As you can see in the interface, each itinerary can contain five different types: Car Rental, Flight, Hotel, Meeting and Public Transportation. These types differ from each other in most of their attributes, so no wonder that algorithms that using them need to provide different behaviour for each type. A good example is the algorithm that decide what to display in the UI – the display of a meeting is very different from that of an hotel (register and see!) The traditional way (or C style) to do that is to have some thing like the following:

switch(item.type) {
case CAR_RENTAL: ...
case FLIGHT: ...
...
}

And the Java incarnation of this code also looks like this:

if(item instanceof CarRental) {
...
} else if(item instanceof Flight) {
...
} else ...

I’m sure that this looks awfully familiar to you. This code has three major problems to it:

  • It is very hard to spot places where one type is not handled – on purpose or by mistake. Since in most cases the actual logic spawns several lines of code it is hard to spot such cases.
  • In case there is a need to add a new type, we need to go over all the places where we need separate logic and add the special case. This is a tedious and error prone process. Furthermore, since it is easy to to forget to throw an UnknownItemTypeException in the end, is will be also easy not to get any exception in places the new type was forgotten.
  • The code is very cumbersome -there are large blocks of code which handle all types, and switch-like ifs (like above) are mixed with other logic control structures.

The solution we chose to all these is to use the visitor design pattern. Using implementations of an ItemVisitor solves these issues:

  • You must always implement all visitXXX() methods. If there’s no need for specific logic for a certain type, then the code clearly shows this by having an empty method. This also adheres to the single choice principle – one of the fundamental principles of software engineering.
  • When new types will be added, then by simply adding new visitNewType() the compiler will notify where all the new logic should be added – since existing visitors won’t have this method.
  • The code is cleaner – instead of having large code block, we have 1-3 lines (depends if we need to return a value from the visitor), and the actual logic is neatly organised into methods

3 thoughts on “Live patterns: Switching to the visitor design pattern

  1. Omar

    Ok, I think you make your point about how much cumbersome could be the code with the first two sniplets. Could you please ilustrate the visitor design patter with an example of your own? The link in the wikipedia it’s ok, but don’t be cheap and complete your post. 😉

    Reply
  2. Dimitris Andreou

    Well, I don’t think this is the life-saver you seem to be describing…

    What visitor buys you here is merely the fact that you don’t have to put an abstract method plus implementations for each distinct type-based desicion (bloating a single file), but create those implementations externally (out of the itinerary source files). I.e. you just managed to avoid putting the type-based code in the types themselves, but somewhere else. Good for you. Where would we be without patterns! 🙂

    Btw, Scala supports the switch you describe (where the compiler notifies you of missed cases).

    Reply
  3. Frood

    @Dimitris:
    The Visitor pattern buys you a bit more than that: You can put the code into the layer it rightfully belongs to. So, the visitors concerning UI go to the UI code and the ones concerning business logic go to the business code etc. Without visitors you have to either put the code into the objects themselves, thus blurring the layers, or replicate the objects inside a layer, being cumbersome and error-prone.
    Besides, in case of hierarchies you can use walkers to traverse object trees, in which visitors act as a kind of beefed-up lambda expressions. Very handy

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *