Back to Basics: Visitor Pattern Explanation with JS Example
April 13, 2013 12:39 pm 2 CommentsVisitor pattern is one of my favourite software engineering design pattern. This technique enables us to extend the functionality of an object without having to modify its class codes. In a nutshell, this patten involves one main object and many visitors objects. The main object will have the ability to “accept” any visitor object and execute the visitor’s generic method to start what the visitor object is suppose to do. On the other hand, any visitor objects will have the ability to accept references from the main object in order to manipulate the main object’s data.
Traditionally, the visitor pattern requires object oriented language that supports single dispatch and method overloading (see http://en.wikipedia.org/wiki/Visitor_pattern for more info). Examples of these languages includes but not limited to C++, Java and many more. This is because the main object will always have to have an accept() method while the visitor object always need to have a visit() method. This visit() method should be able to be overloaded and accepts inputs of different types and at runtime the program decides which visit() method to run.
An example of the code for visitors object in a full object oriented language would be something like:
1 2 3 4 5 6 7 8 9 |
class visitorPlumber { public void visit(Faucet problemArea) { // fix problem area to do with Faucet } public void visit(WashBasin problemArea) { // fix the problem area to do with WashBasin } } |
With an implementation like the above we don’t have to worry about what kind of data is being passed in to the visit method. At runtime visitorPlumber will know which visit function to run based on the type of the input to the visit method. Of course like I said previously we need a language with full method overloading feature.
Explanation with JavaScript
Today however, we will take the visitor pattern concept and we’ll apply it to JavaScript implementation. Of course JavaScript does not have the ability to do method overloading, however I want to explain the basic understanding of visitor pattern to all of you, because I think the concept may not be easy to understand for the first time. Also like anything in Computer Science we can always apply different concepts from other programming language to suit our needs in our current application.
To do this, I’ll use House, Home Inspector and Tradesmen analogy. Let’s assume we have a house with a number of issues. The home inspector has been called in to check on the house, his job is to list every parts that have problems and give it to us, the owner. Of course the home inspector cannot fix it himself, he has to call some tradesmen. For the purpose of our exercise, we have: plumber, electrician and gardener.
The House
Let’s start with building our house class with a couple of problems to start with. Well, maybe we bought an old house then….since it has a couple issues to begin with. Anyway, the house object will look like this.
1 2 3 4 5 6 7 8 9 10 |
var houseWithProblems = { plumbing: "leaky faucet", garageDoor: "broken motor", backyard: "weed infestation", //accept function which will receive the visitor accept: function(visitor) { visitor.visit(this); } } |
As you can see above, we started with a whole host of problems. We have leaky faucet, broken garage door motor and weed infestation in the backyard (ouch!). So, if we think abou the house literally, what do we need to do to solve all of those problems?
We can do it ourselves of course, but not all of us are licensed plumbers and electricians; not to mention garden experts. Alternatively, we can also add some functions to the house to fix its plumbing, garage door and backyard. But that wouldn’t be practical isn’t it? Unless your house has some kind of AI and robotic arms.
So, in this case our solution is to add the ability to our house to accept visitors. Which is why in the sample code above we have the accept function. To continue with our analogy, the accept function enables the house to accept visits from the trades professionals.
However in addition to that, the function also allows or giving permission for the visitors (tradesmen) to do what they have to do in order to fix the problems in the house. In our code, this is the visitor.visit(this) call. In this call to the visitor’s function visit, the House passess a reference of itself, essentially giving full access for the visitor to manipulate the house.
The visitors objects, which we will discuss next will have the ability to perform actions for the house. Notice that we pass a reference and not a copy of the house object, by doing this we make sure that we manipulate the right house object and not a copy of it. We wouldn’t want our tradesmen to fix the wrong house after all :)
The Visitors: Home Inspector
The home inspector (could be ourselves or someone else) is a person who checks the house for the curent problems. In our example, he simply writes in our list the current status of the house elements.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
var visitorHomeInspector = { visit: function(home) { $('#specs').append("<li class='header'>Current house status:</li>"); //let's display this on our list $('#specs').append("<li> Plumbing: " + home.plumbing + "</li>"); $('#specs').append("<li> Garage Door: " + home.garageDoor + "</li>"); $('#specs').append("<li> Backyard: " + home.backyard + "</li>"); } } |
Quite simple, the visit method of the home inspector accepts a reference to our HouseWithProblems object, we call this home. Basically this object access the plumbing, garageDoor and backyard properties directly and outputs it to our <ul> unordered list. Simple.
The Visitors: Tradesmen
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
var visitorPlumber = { visit: function(home) { //let's fix the plumbing home.plumbing = "All good!" } } var visitorElectrician = { visit: function(home) { //let's fix the garage door home.garageDoor = "All good!" } } var visitorGardener = { visit: function(home) { //let's fix the garage door home.backyard = "All good! No more weeds" } } |
This is very simple implementation, basically each of those visitors (tradesmen) set the status of each of their areas to fix to “All Good”. Of course for the purpose of this exercise we assume that they did really great jobs and the faucet, garage door motor and weed infestations are handled and fixed with top notch quality!
But how exactly are we going to bring all of these accept and visits together? Well, we’ll have some action buttons for our exercise.
The Action Call
The action calls consist of simple jQuery click even handler in our example. We’ll take the display action for example.
1 2 3 4 5 6 7 8 9 |
$('.display').click(function() { houseWithProblems.accept(visitorHomeInspector); $('.step1').fadeOut('slow', function() { $('.step2').fadeIn('slow'); }); //scroll to bottom scrollLatestStatus(); }); |
In the code above, when we click on the display button, the function calls houseWithProblem’s accept method and pass the reference of the visitorHomeInspector. Now from there, the accept method will call the visit method if the visitorHomeInspector object. In essence giving the permission for the home inspector to do whatever he needs to do in the house, which is listing the current statuses of the problems.
The other action calls for plumber, electrician and gardeners consist of the same logic. Call accept method, pass in the visitor object then let the visitor object do their visit action.
Demonstration
To show you an example of what each visits to the house have an effect on, feel free to play with the jsFiddle snippet below.
For the full jsFiddle example, visit this page.
Recap
So to recap what we have just discussed about visitor pattern, here are a few key points:
- Visitor pattern gives us the ability to add much more functionality to an object, without having to modify the object’s class codes
- To use this technique we need the main object to visit and visitor objects
- The main object to visit must have the method accept to be able to receive visitors
- The visitor objects must have the method visit to be called by the accept method of the main object
In conclusion, visitor pattern is extremely handy. However one must be careful when using this technique as overzealous use of visitors might lead to spaghetti code and confusion in the future.
Tags: design pattern, javascript, jsfiddle, object oriented, visitor patternCategorised in: Back to Basic, Coding