Responsible JavaScript: Using Factories

Wikipedia has a wonderfully dry definition of the factory pattern:

The factory pattern is a creational design pattern used in software development to encapsulate the processes involved in the creation of objects.

The creation of an object often requires complex processes not appropriate to include within a composing object. The object’s creation may lead to a significant duplication of code, may require information not accessible to the composing object, may not provide a sufficient level of abstraction, or may otherwise not be part of the composing object’s concerns.

Some of the processes required in the creation of an object include determining which object to create, managing the lifetime of the object, and managing specialized build-up and tear-down concerns of the object.

Essentially what we’re talking about here is complexity management. Complexity is disease that infects all programs and APIs at some point and JavaScript is certainly no exception. Just look at the awful code it takes to reliably create an XMLHttpRequest instance:

var XHRFactory = function () {
    if (window.XMLHttpRequest) {
        return new XMLHttpRequest;
    }
    else if (window.ActiveXObject) {
        var xhr, axo, ex, objects;

        objects = ['Microsoft', 'Msxml2', 'Msxml3'];

        for (var i = 0; i < objects.length; i++) {
            axo = objects[i] + '.XMLHTTP';

            try {
                xhr = new ActiveXObject(axo);
                return xhr;
            }
            catch (ex) {};
        }

        throw 'Unable to create XHR object.';
    }
    else {
        throw "XMLHttp is not supported.";
    }
};

To make matters worse, JavaScript has a nasty constructor implementation which if used improperly, can cause lots of hard to trace errors. For example, this problem which I outlined in a previous post on the topic:

var Person = function (name, location) {
    this.name = name;
    this.location = location;
};

var mike = new Person('Mike G.', 'NYC');
var alex = Person('Alex H.', 'NYC');

Paste that block into firebug and tell me how long it takes you to find the root cause of the problem.

Not only do factories help manage complexity, they also manage dangerous problems with the language. Simply put, factories in JavaScript should be a considered a best practice of responsible programmers.

Update: Advanced Factories

Ok, enough bashing on JavaScript. Lets switch gears a moment and talk about one of the more interesting aspects of the language: its functional nature.

JavaScript is a functional language and as such, functions can be treated as you would any other data type. You can store functions in variables:

var hello = function () {
    console.log('Hello, world!');
};

… pass functions as arguments to other functions:

var foo = document.getElementById('foo');

foo.addEventListener('click', function(event) {
    console.log('You clicked foo.');
}, false);

… and even return functions from functions:

var functionFactory = function (name) {
    return function () {
        console.log('I am ' + name + '. Thanks for running me');
    };
};

mike = functionFactory('Mike');
owen = functionFactory('Owen');

mike();
mike();
owen();

functionFactory('cool eh?')();

Function factories have so many uses. The deeper you go into JavaScript, the more you find yourself using function factories. As Peter Michaux has shown us via his lazy function pattern, it can be a fantastic way to save on resources. Likewise, we can take the same concept and apply it in a way I like to call Load Time Configuration.

Take a look at my XHR code above. Immagine the pain that your browser has to go through every time you call that function. First it has to check to see if it supports the standard XHR object. If not, then it has to go though all the foulness of MSXML juggling.

Lets simplify things a bit and make it so that it bakes the appropriate function on page load. This will eliminate the initial check:

var XHRFactory = (function () {
    if (window.XMLHttpRequest) {

        return function () {
            return new XMLHttpRequest;
        }

    }
    else if (window.ActiveXObject) {

        return function () {
            var xhr, axo, ex, objects;

            objects = ['Microsoft', 'Msxml2', 'Msxml3'];

            for (var i = 0; i < objects.length; i++) {
                axo = objects[i] + '.XMLHTTP';

                try {
                    xhr = new ActiveXObject(axo);
                    return xhr;
                }
                catch (ex) {};
            }

            throw 'Unable to create XHR object.';
        }

    }
    else {

        return function () {
            throw "XMLHttp is not supported.";
        }

    }
})();

As you may have imagined, this is also useful when dealing with the event registration problem. I’ll save that for a future article. In the mean time, consider that an exercise to practice with.

Enjoy!

This entry was posted in JavaScript. Bookmark the permalink.

One Response to Responsible JavaScript: Using Factories

  1. Fire Crow says:

    That this.location bug is totally wild, I like factories as well, I was considering using a function of the class, but having it on every instance is confusing.

    a separate factory object is really nice.

Leave a Reply

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

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>