Singleton Design Patterns com Javascript
Leia em: 6 minutosSingleton é um Design Patterns.
Este padrão fica responsável por criar um objeto e garantir uma única instância de sua classe ou função construtora.
Para implementação de um objeto Singleton, precisamos pensar em uma forma de disponibilizarmos uma propriedade no objeto, de maneira que possamos acessá-lo direto sem a necessidade de uma instância.
Implementação no ECMAScript 5
Vou mostrar uma implementação básica em javascript na versão do ECMAScript 5:
window.Foo = (function() {
var _instance = void 0;
Foo.getInstance = function() {
return !!_instance ? _instance : _instance = new Foo();
};
function Foo() {
console.log('new instance');
}
return Foo;
})();
Foo.getInstance() // => new instance
Foo.getInstance() // => return object instantied
De início declarei uma variável interna chamada de _instance
. A função desta variável é guardar o estado atual da instância.
Logo após foi definido uma propriedade chamada de getInstance
dentro do objeto Foo
, essa função implementa nossa regra de Singleton.
A primeira e única instrução que encontramos dentro da nossa propriedade getInstance
é um ternário que verifica o estado da variável _instance
.
Quando a variável for nula, significa que estamos passando ali pela primeira vez, então o seguinte trecho de código é executado: _instance = new Foo()
.
Das próximas n vezes já teremos a instância do objeto armazenada na variável _instance
então apenas o retorno é feito.
Implementação no ECMAScript 6
Para finalizar irei mostrar um exemplo de Singleton utilizando o ECMAScript 6:
let _instance = Symbol();
let _singletonEnforcer = Symbol();
class Foo {
constructor(enforce) {
console.log('new instance');
if (enforce !== _singletonEnforcer) {
throw('Cannot constructor singleton')
}
}
static get getInstance() {
if(!this[_instance]) {
this[_instance] = new Foo(_singletonEnforcer);
}
return this[_instance];
}
}
Foo.getInstance // => new instance
Foo.getInstance // => return object instantied
Esta lógica é quase parecida com a anterior.
Neste caso criei duas variável fora do escopo da classe, com o nome de _instance
e uma outra chamada de _singletonEnforcer
ambas definidas como símbolo.
Ao criar a classe Foo
defini um método estático chamado getInstance
que será acessado através da class Foo
sem necessidade de instância.
Quando o método getInstance
é chamado pela primeira vez, ele verifica se existe uma propriedade definida que não esteja nula !this[_instance]
. Caso a propriedade ainda não esteja definida ele criar e atribui a instância como valor: this[_instance] = new Foo(_singletonEnforcer);
, caso haja a propriedade ele apenas retorna return this[_instance]
.
Para finalizar, na função construtora da classe eu envio _singletonEnforcer
como uma forma de garantir que a nova instância esteja sendo chamada sempre de dentro da função getInstance
, caso o valor seja diferente uma excessão é lançada throw('Cannot constructor singleton')
, impedindo que a classe seja inicializada.
Finalizando
Imagine um objeto que tem a função de abrir uma conexão com o banco de dados antes de executar qualquer operação.
Se a cada operação abrirmos uma conexão, com certeza perderemos muito a qualidade de processamento, podendo até travar as conexões.
Mas se utilizarmos uma classe Singleton para fazer as conexões, evitaremos essa sobrecarga pois estaremos utilizando da mesma instância para todas as operações.
O conceito de Singleton pode ser aplicado em várias outras lógicas de programação sempre que quiser garantir a existência de apenas uma instância de uma classe (se estiver usando ES6) ou de uma função construtura (se estiver usando ES5).
Comentários:
Deixe sua dúvida, sugestão ou crítica, estou ansioso para saber tudo o que você achou sobre este post: