My JavaScript book is out! Don't miss the opportunity to upgrade your beginner or average dev skills.

Sunday, February 25, 2007

A better Singleton pattern example

JavaScript Singleton examples are often not so correct.
In these pages for example, top Google search results, any showed code is a Singleton design pattern:


Why these examples are not good enought?


As You can see, Singleton uses a private constructor and a static public method to get a uniq object instance.

// Java example
public class Singleton {

// Private constructor suppresses generation of a (public) default constructor
private Singleton() {}

private static class SingletonHolder {
private static Singleton instance = new Singleton();
}

public static Singleton getInstance() {
return SingletonHolder.instance;
}
}

In JavaScript a constructor can't be private but It should has a private variable so why we should use a public static instance property when we could have a private one?

// Singleton pattern with JavaScript
function Singleton(instance) {
if(!Singleton.getInstance) {
Singleton.getInstance = function(){
return instance;
}; instance = new Singleton;
};
}(new Singleton);

Constructor is public but it's assigned directly to have a single private instance that will be always the same everytime we call Singleton.getInstance public method.

function Me(
instance // private class instance
) {

// public static method (Singleton design pattern)
if(!Me.getInstance) {
Me.getInstance = function(){
return instance;
}; instance = new Me;
};

// generic public properties and methods

this.name = "Andrea";
this.surname = "Giammarchi";

this.whois = function(){
return this.name.concat(" ", this.surname);
};


}(new Me);


// and now try to modify instance ...
var me = Me.getInstance(),
others = new Me({name:"No", surname:"Others"}),
you = Me.getInstance();

you.constructor.prototype = {
name:"No",
surname:"Changes"
};

Me.instance = {name:"Private", surname:"Scope"};

alert([
me.whois(),
others.whois(),
you.whois()
].join("\n"));

alert(me === you && you === Me.getInstance());

The result is my name on first alert and true on second.
Is there a simple way to implement singleton with every class ? Of course :-)

Function.prototype.Singleton = function(instance){
if(!this.getInstance) {
this.getInstance = function(){
return instance;
};
};
};


function Me(){
this.name = "Andrea";
this.surname = "Giammarchi";
this.whois = function(){
return this.name.concat(" ", this.surname);
};
};
Me.Singleton(new Me);

var me = Me.getInstance();
me.blog = "webreflection";
alert(me === Me.getInstance() && me.blog === Me.getInstance().blog);



P.S. for MarCamp "fast demo": sorry guys, bad cut and paste on showed example, just add this line if You want to test the example (damn time !!!)
instance = new Singleton;

after getInstance declaration

5 comments:

kangax said...

Now, how can we imlpement an observer pattern? :)

Anonymous said...

I'm not a pro in javascript, but as far as i see, your singleton pattern is not so right. The examples from other websites that you said they were wrong, seem to me more right than your implementation of the singleton pattern.

Andrea Giammarchi said...

chris, I accept any kind of comments, but I prefer those constructive. Any better example?

Benoît Fleury said...

What about that?

var Singleton = (function() {
var instance = null;
return function() {
if (instance == null) {
// initialize instance
}
return instance;
}
})();

scarsick said...

/*
This is my implementation of the singleton pattern from Head First - Design Patterns. One thing that people always forget in their singleton patterns is to also implement the lazy-instanciation, which might be important in case of resource intensive objects.
*/

var Singleton = (function(){
var _instance = null;

return {
getInstance:function(){
if (!_instance)
_instance = (function(){
var _name = 'Supertone';

return {
sayName:function(){
alert('I am ' + _name + '!');
}
}
})();
return _instance;
}
}
})();