Tuesday, November 2, 2010

Javascript Design Patterns - Singleton Pattern

The singleton is one of the most basic, but useful, patterns in JavaScript, and one that you will probably use more than any other.

It provides a way to group code into a logical unit that can be accessed through a single variable.

By ensuring that there is only one copy of a singleton object, you know that all of your code makes use of the same global resource.

Singleton classes have many uses in JavaScript:

- They can be used for namespacing, which reduces the number of global variables in your pages.

- They can be used to encapsulate browser differences through a technique known as branching, which allows you to use common utility functions without worrying about browser sniffing.

- they can be used to organize your code in a consistent manner, which increases the readability and maintainability of your pages.

This pattern is extremely important in JavaScript, maybe more so than in any other language. Using global variables in your pages presents a huge risk, and a namespace created with a singleton is one of the best ways to remove those global variables.

The Basic Structure of the Singleton

It is essentially an object literal containing methods and attributes that have been grouped together because they are somehow related:

/* Basic Singleton. */
var Singleton = { 
    attribute1: true, 
    attribute2: 10,
   
    method1: function() {
    
    }, 
    method2: function(arg) {
    
    } 
 };

You should be aware that there is nothing in the language to prevent object modification from happening. If you do need to protect certain variables, you can always define them within a closure, as discussed in Encapsulation post (book reference Chapter 3).


Namespacing

A singleton object consists of two parts: the object itself, containing the members (both methods and attributes) within it, and the variable used to access it.
The variable is usually global, so that the singleton object can be accessed anywhere in the page. This is a key feature of the singleton pattern.

Namespacing is a large part of responsible programming in Javascript. Because everything can be overwritten, it is very easy to wipe out a variable, a function, or even a complete class without even knowing it.

These types of errors are extremely time-consuming to find.

In a lot of pages today, there is code from more than one source. There may be library code, advertiser code, and badge code in addition to anything you write. All of these variables exist within the global namespace of the page. In order to prevent collisions, you can put "all" of your code under a single variable. You can then group all of your code and data within objects or singletons under that single global variable.

Singleton with Private Members

- Using the Underscore Notation

- Using Closures

---------

Singleton As an Object Literal:
MyNamespace.Singleton = {};

/* Singleton with Private Members, step 1. */
MyNamespace.Singleton = function() { 
   return {};
}();


Some programmers find it useful to add another pair of parentheses around the function to denote that it is being executed as soon as it is declared. This is especially useful if the singleton is large. You can see at a glance that the function is used only to create a closure.
/* Singleton with Private Members, step 1. */
MyNamespace.Singleton = (function() { 
  return {};
})();


You can add public members to that singleton in the same manner as before by adding them to the object literal that gets returned:
/* Singleton with Private Members, step 2. */
MyNamespace.Singleton = (function() { 
   return { // Public members.
      publicAttribute1: true, 
      publicAttribute2: 10,

      publicMethod1: function() { 
      //…
      },
      publicMethod2: function(args) { 
      //...
      } 
    };
})();

Important

So why bother adding a function wrapper if it produces the same object that you can create using nothing more than an object literal?

Because that function wrapper creates a closure to add true private members.

Any variable or function declared within the anonymous function (but not within the object literal) is accessible only to other functions declared within that same closure.

The closure is maintained even after the anonymous function has returned, so the functions and variables declared within it are always accessible within (and only within) the returned object.

Here is how to add private members to the anonymous function:

/* Singleton with Private Members, step 3. */
MyNamespace.Singleton = (function() { 
      // Private members. 
      var privateAttribute1 = false; 
      var privateAttribute2 = [1, 2, 3];
    function privateMethod1() { 
          //...
    } 
    function privateMethod2(args) {
          //...
    }
    
     return { 
         // Public members. 
         publicAttribute1: true, 
         publicAttribute2: 10,
      
         publicMethod1: function() { 
              //…
         }, 
         publicMethod2: function(args) {
              //...
         } 
     };
})();

This particular singleton pattern is also known as the module pattern, referring to the fact that it modularizes and namespaces a set of related methods and attributes.

Using this pattern, you get all of the advantage of true private members with one of the drawbacks because this is only instantiated once.
That is what makes the singleton pattern one of the most popular and widely used in JavaScript.

Lazy Instantiation

To be Continued...

No comments:

Post a Comment