



























Wikipedia describes the singleton design pattern as:
The singleton pattern is a design pattern that restricts the instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system. The concept is sometimes generalized to systems that operate more efficiently when only one object exists, or that restrict the instantiation to a certain number of objects. The term comes from the mathematical concept of a singleton.
Singleton is one of the most well known and also hated design patterns, all the time. It is very easy to implement a basic version of the singleton pattern so that’s the reason it is that well known. But if we look deeper into different details, there are plenty of problems, which may happen because of poor implementation:
getInstance method of the singleton.Thanks God we don’t have to consider all these corner cases in JavaScript.
The simplest singleton implementation in JavaScript is:
And yes – this is singleton!
Addy Osmani suggests the following implementation at his book “Learning JavaScript Design Patterns”:
var mySingleton = (function () {
// Instance stores a reference to the Singleton
var instance;
function init() {
// Singleton
// Private methods and variables
function privateMethod(){
console.log( "I am private" );
}
var privateVariable = "Im also private";
var privateRandomNumber = Math.random();
return {
// Public methods and variables
publicMethod: function () {
console.log( "The public can see me!" );
},
publicProperty: "I am also public",
getRandomNumber: function() {
return privateRandomNumber;
}
};
};
return {
// Get the Singleton instance if one exists
// or create one if it doesn't
getInstance: function () {
if ( !instance ) {
instance = init();
}
return instance;
}
};
})();This implementation is based on the module pattern. The module pattern is applied two times – the first application aims to provide the actual singleton and keeps the private data/behavior inside a closure. The second usage of the module pattern aims to provide the public interface used for getting the singleton object, which is kept inside a closure.
It is absolutely valid and useful implementation:
As drawback I can point the lack of specific “type” of the singleton (i.e. more specific than object), which won’t allow you to use the operator instanceof. I can argue that the definition of the private members can lead to poor unit testing, but if they are private, they are not intended for testing anyway.
Another implementation of singleton, which I found in the network is “The best Singleton pattern”:
(function(global) {
"use strict";
var MySingletonClass = function() {
if ( MySingletonClass.prototype._singletonInstance ) {
return MySingletonClass.prototype._singletonInstance;
}
MySingletonClass.prototype._singletonInstance = this;
this.Foo = function() {
// ...
};
};
var a = new MySingletonClass();
var b = MySingletonClass();
//a === b
global.MySingleton = a; //or b
}(window));Here are the main advantages of this implementation:
instanceof operatorAs drawback I can state the fact that you can easy change the prototype property _singletonInstance of your singleton. This way, when MySingleton is called once again, it will create a new object:
Object.getPrototypeOf(MySingleton)._singletonInstance = null;Implementation I use is formed by combining both approaches from above:
var MySingleton = (function () {
var INSTANCE;
function MySingleton(foo) {
if (!(this instanceof MySingleton)) {
return new MySingleton(foo);
}
this.foo = foo;
}
MySingleton.prototype.bar = function () {
//do something;
};
return {
init: function () {
if (!INSTANCE) {
return INSTANCE = MySingleton.apply(null, arguments);
}
return INSTANCE;
},
getInstance: function () {
if (!INSTANCE) {
return this.init.apply(this, arguments);
}
return INSTANCE;
}
};
}());In this example we use the module pattern once again, in order to enclose the singleton implementation into a lexical closure and provide a public interface for getting its instance.
Sometimes you need to pass arguments when initializing a singleton for first time. This is easy achieved using the method init. The init method is not aware of the arguments required by the singleton – all it does is to forward the call to the internal MySingleton function with context null. Inside the implementation of the MySingleton constructor function we make a check whether the current context – this is of type MySingleton, if it isn’t, then this means that MySingleton is not called with the new operator, so we recursively call new MySingleton with the required parameters.
What are the benefits we get from this implementation:
applyinstanceof operatorAs drawback, I can state that I feel unnatural for this implementation to use “private” data/behavior – but yes, it is possible if you define them in the lexical closure of the module pattern.
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。