VYRE Company:Blog

Javascript Flyweight Pattern

13.01.2010 12:58 ( 0 comments )

by Gary Chisholm

 

One of the big concerns at the moment within Professional Services is efficiency - not just for us but also our code. The flyweight pattern has been something I've been using for a few weeks now and has been a perfect solution to a lot of slow, sluggish and repetitive portions of code.

 

What is the flyweight pattern?

A flyweight is a way of taking many small, similar objects and placing the shared information into one, external object. In relation to Javascript our objects are functions. The goal of the flyweight pattern is to make the triggering objects, such as buttons, have no responsibility for what actions it performs and to abstract that responsibility upwards to a global flyweight manager.

Although the term flyweight is initially a boxing phrase try to think of it in terms of a pond. A fish opens its mouth (the event), bubbles raise to the surface (the bubbling) a fly sitting on the top flies away when the bubble reaches the surface (the action). In this example you can easily transpose the fish opening its mouth to a button being clicked, the bubbles as the bubbling effect (you can see I'm really trying hard with this metaphor) and the fly flying away to some function being run.

Generally speaking a flyweight is a way of minimising code duplication, minimising page weight and removing individual responsibility from each individual object by having a shared resource. Flyweights are exceptionally handy in Javascript because of the bubbling effect inherent with the language; when an element, such as a button, is clicked that event gets bubbled upwards to all parent containers letting each one know that something below it has been clicked, this is something that happens all the time anyway so why not take advantage of it.

Are you with me so far?

Why should I use the flyweight pattern?

The flyweight pattern is ideal when you have a lot of small, easily managed but similar objects within a page that share some crucial information; in most cases this will probably be a click event. Rather than binding a click event or adding an onClick handler to each button or element on a page you can simply attach a flyweight to the top <div> tag which will listen for click events coming from below and, depending on the context of the click event either a class or id of the button being clicked, will know what to do with it. This converts many independent objects into a few shared objects which is very useful in Javascript where complex code, jQuery I'm looking at you, can hog all the browser memory.

In the Virgin project this has been used mainly for our image galleries where we have had perhaps 20 or 30 galleries on one page, one for each hotel or holiday, each with its own previous, next and magnify buttons. The behaviour of each button has always been the same for each containing gallery relative to its own images. Using flyweights has meant that rather than treating each gallery as its own we can manage all these click events in one place and determining what the buttons should do by their classes.

Another benefit, due to the flyweight being external from the buttons themselves, was with pagination from an Ajax Search Result. By using the flyweights it meant that each time we paginated to a new set of results the flyweights remained unchanged and still worked exactly as they did before for our new results without having any more code or having to reload any of our functions.

How do I use it?

In the below example I've created a FlyweightManager namespace to contain all our flyweight functions. As you can see I'm using jQuery to bind a click event to the div element with the ID of 'wrap'. The unbind event is to make sure that only the flyweight is bound to the div by removing any others before we bind the flyweight.

The target element is the DOM element that has been clicked and depending on what class the target element has depends on what function we call; in this case if an <a> tag with a class of 'hello' has been clicked we want to call the 'sayHello' function.

 


FlyweightManager = {
attachFlyWeights : function () {
var self = this;
jQuery("#wrap").unbind().bind("click", function(e) {
var targetElement = jQuery(e.originalTarget || e.srcElement);

if( targetElement.is("a.hello, a.goodbye") ) {
self.handleHelloGoodbye( targetElement );
}
});               
},

handleHelloGoodbye : function ( button ) {
alert( button.className + " world!" );
}   
}

FlyweightManager.attachFlyweights();

 



The result will either alert a "hello world!" or "goodbye world!" message to the user depending on which <a> tag has been clicked.

Obviously this was just a quick explanation to make you aware of something I've found cool and has helped me a lot. If you're interested in learning more about the Flyweight pattern the YUI blog is currently hosting a chapter on the flyweight pattern from a new Apres book "Pro JavaScript Design Patterns" by Ross Harmes and Dustin Diaz (knows a lot about corn and even more about Javascript).

Check it out here (http://yuiblog.com/assets/projsdesignpatterns-ch9.pdf).

 

Comments