Singleton em JS
Leia em: 6 minutos![](/assets/posts/js/singleton-em-js-big-70391f44a3116ee097bea5c3d95c3b7b.png)
Singleton é um design pattern.
Este padrão fica responsável por criar um objeto e garantir uma única instância de sua classe.
Um conceito principal para implementação de um objeto singleton é que precisamos pensar em um forma de disponibilizarmos uma propriedade no objeto de maneira que possamos acessa-lo direto sem a necessidade de uma instância.
Implementação no ES5
Vou mostrar uma implementação básica em javascript na versão do ECMA 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 _instance
. A função desta variável é guardar o estado da instância enquanto nosso script estiver sendo executado.
Logo após foi definido uma propriedade chamada de getInstance
em Foo
que tem como valor uma função que executará nossa regra de singleton. Esta função pode ser chamada direto através do objeto Foo
.
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 estiver nula significa que estamos chamando a propriedade getInstance
pela primeira vez, então o seguinte trecho de código é executado: _instance = new Foo()
(uma nova instância de Foo
é gerado e armazenado na variável _instance
).
Das próximas n vezes que chamarmos a propriedade getInstance
através do objeto Foo
ja teremos a instância do objeto armazenada na variável getInstance
então é feito apenas o retorno da variável que guarda a instância do objeto Foo
.
Implementação no ES6
Para finalizar irei mostrar um exemplo de singleton utilizando o ECMA 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 é um pouco diferente da 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 pois a principal característica dos símbolos é serem únicos e imutáveis, e isto é o suficiente para criamos propriedades na nossa classe que seja única.
Ao criar a classe Foo
defini um método estático chamado getInstance
que será responsável por controlar se há necessidade de uma nova instância ou se simplesmente devolve a instância já criada.
Note que quando chamamos o método getInstance
a primeira coisa que é verificada é se existe uma propriedade definida que não esteja nula !this[_instance]
. Caso o valor seja null
ele criar esta propriedade na classe Foo
e atribui como valor a instância da própria classe Foo
: this[_instance] = new Foo(_singletonEnforcer);
, caso o valor da propriedade não seja null
ele passa para próxima instrução.
A próxima instrução retorna essa propriedade: return this[_instance]
.
Perceba que ao instanciar a classe Foo
eu mando de parâmetro no construtor a váriavel _singletonEnforcer
e dentro do construtor da classe eu verifico se o parâmetro que chega é o mesmo valor de _singletonEnforcer
, caso seja um valor diferente eu disparo uma exception
pois terei certeza de que a instância não foi definida de dentro da função getInstance
.
Exemplo de uso
Imagine um objeto que tem a função de abrir um 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 processamente, podendo até travar as conexões.
Mas se utilizarmos uma classe singleton para fazer esta conexão, 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.
Comentários:
Deixe sua dúvida, sugestão ou crítica, estou ancioso para saber tudo que você achou sobre este post: