First of all, let us look at how the simplest yet
commonly-used pattern, the Singleton pattern, is achieved in JavaScript.
(1) Concept
As a very fundamental and important pattern, the Singleton pattern
is used to guarantee that there is one and only one instance for a given class,
and provide an overall point to visit it.
Under a lot of practical circumstances, you usually need to
insure there is one and only one instance related to a specified class. For
this, traditional languages often resort to embedding a static variable in the
class definition, setting up this variable in the first instance and making
corresponding verifications whenever using the constructor of the instance.
That is to say, no matter how many instantiations you have established, the
static variable only relates to one instance. To prevent from instantiating a
class more than one time, you need to declare the constructor function as
private type, so that you can only establish the instance in the static method.
In the JavaScript language, although we still can specify a
static method to construct an object, because we cannot make use of the "private"
characteristic of the constructor function to forbid creating more than one instances,
it is not as simple as that imagined to completely carry out the Singleton
pattern.
(2) Example
Assume that we want to create an object which serves as a
tool helper, including no business logic and any data required to be changed.
Obviously, when you use such an object you do not need to instantiate the class
each time -- one and only instance is enough for global invocation.
According to the analysis above, we can use JavaScript code
(Listing 1) to carry out the Singleton pattern. This can insure there is one
and only one instance relating to a given class, and provide an overall site to
access it.
Listing 1: Establish the Singleton pattern in the
JavaScript
function Singleton(){
this.property1=”hello”;
this.methodl=function(x,y){
return x+y;
}
//define a static property
Singleton._instance_=null;
Singleton.getInstance=function(){
if(this._instance_==null){
//if there is no instance for class Singleton,
then create one
this._instance_=new Singleton();
}
//return the instance of class Singleton
return this._instance_;
};
The getInstance method first judges whether
the static property Singleton._instance_ is null. If so,
then it sets up an instance of the Singleton object and stores it in property Singleton._instance_. Finally, the Singleton._instance_
property is returned.
As for the usage of the Singleton class, it is easy:
Listing 2
//return only one instance
var instA =Singleton.getInstance();
Regrettably, the above code cannot prevent a user from instantiating
the Singleton class directly. For example, it is still OK to set up an instance
of the Singleton class through the following sentence.
Listing 3
var instA =new Singleton ();
And later on, it is also valid to make the following invocations.
Listing 4
alert(typeof(instA));
alert(instA.property1);
Therefore, we need a further modification with the
definition of the Singleton structure so that you can only instantiate the Singleton
class in the Singleton.getInstance method. Please look
at the following solution.
Listing 5
function Singleton(){
if(Singleton.caller!=Singleton.getInstance){
throw new Error(”Can not new
Singleton instance!”);
}
…… (omitted)
}
Now, whenever the user tries to establish several instances,
an exception is thrown out. However, it still feels some awkward, doesn't it? But
anyway, we have already used the above-mentioned solution to achieve our initial
purpose-- creating one and only instance of a given class.
Next, we start to discuss the third method (also a second to
none method). This kind of method skillfully makes use of JavaScript's support
toward "anonymous" function to indirectly achieve the target of
forbidding the access to the constructor function of class Singleton, which preferably
imitates the characteristic of private constructor function and perfectly solves
the problem that JavaScript carries out the Singleton pattern. Listing 6 below
shows this kind of best solution.
Listing 6: with the help of "anonymous"
function to implement the Singleton pattern in JavaScript
<script type="text/javascript">
(function(){
//SingletonFactory Interface
SingletonFactory = {
getInstance : getInstance
}
//private classes
function SingletonObject()
{
SingletonObject.prototype.methodA =
function()
{
alert('methodA');
}
SingletonObject.prototype.methodB =
function()
{
alert('methodB');
}
SingletonObject.instance = this;
}
//SingletonFactory implementions
function getInstance()
{
if(SingletonObject.instance == null)
return new SingletonObject();
else
return SingletonObject.instance;
}
})();
var instA = null;
try
{
alert("Try to create an instance using new SingletonObject()!");
instA = new SingletonObject();
}
catch(e){
alert("You cannot access the constructor of SingletonObject externally!");
}
//create the target instance with the help of the
// static method from the Factory
instA = SingletonFactory.getInstance();
var instB = SingletonFactory.getInstance();
instA.methodA();
instB.methodA();
alert(instA == instB); //OK
</script>
Ha, the third solution finally finds out a way to it by digging
into the ability of "poor" JavaScript, but finally obtains decent
effect.