GoF, p. 127
Singleton
Singleton
Uma única instância na aplicação inteira, com ponto de acesso global.
Garantir que uma classe tenha somente uma instância e fornecer um ponto global de acesso a ela.
O governo de um país
Um país tem um único governo oficial. Independentemente de quem sejam as pessoas nos cargos, “o Governo do Brasil” é um ponto de acesso global a uma entidade única. Você não instancia um segundo governo — você pede o que já existe.
Dois problemas ao mesmo tempo (e é por isso que o padrão é criticado): garantir instância única de um recurso compartilhado (uma conexão, um cache) e oferecer acesso global a ele. Uma variável global resolveria o acesso, mas qualquer código poderia sobrescrevê-la.
Torne o construtor privado e exponha um método estático que cria a instância na primeira chamada e devolve a mesma daí em diante.
- Testes que passam sozinhos e falham em suíte (estado vazando pelo singleton).
Algo.getInstance()no meio de uma regra de negócio.
Estrutura
- Singleton
- Guarda a instância única em campo estático e expõe `getInstance()`; construtor privado.
Implementação
class Configuracao {
static #instancia = null;
#valores;
constructor() {
if (Configuracao.#instancia) {
throw new Error('Use Configuracao.getInstance()');
}
// Inicialização cara: só acontece uma vez na vida do processo.
this.#valores = { api: 'https://api.exemplo.com', timeout: 5000, debug: false };
console.log('⚙️ configuração carregada (uma única vez)');
}
static getInstance() {
// Inicialização preguiçosa: só cria quando alguém realmente precisa.
if (!Configuracao.#instancia) Configuracao.#instancia = new Configuracao();
return Configuracao.#instancia;
}
get(chave) { return this.#valores[chave]; }
set(chave, valor) { this.#valores[chave] = valor; }
}
const a = Configuracao.getInstance();
const b = Configuracao.getInstance();
console.log(a === b); // true — é o MESMO objeto
a.set('debug', true);
console.log(b.get('debug')); // true — estado compartilhado
// ⚠️ Em JavaScript com módulos ES, este é o Singleton idiomático:
// export default new Configuracao();
// O sistema de módulos já garante que o módulo é avaliado uma única vez. - java.lang.Runtime.getRuntime()
- java.awt.Desktop.getDesktop()
- O objeto `window` / `console` do navegador
- Containers de DI geralmente registram serviços como singletons — sem o padrão GoF
Consequências
- Garante instância única de verdade.
- Ponto de acesso global bem definido.
- Inicialização preguiçosa: só paga o custo quando alguém usa.
- Viola o Princípio da Responsabilidade Única: resolve unicidade E acesso global.
- Esconde dependências — a classe que o usa não declara que depende dele.
- Dificulta testes: não dá para injetar um dublê facilmente, e o estado vaza entre testes.
- Exige tratamento especial em ambientes multithread.
- É, na prática, uma variável global com um disfarce elegante.
- Existe um recurso genuinamente único e compartilhado (pool de conexões, logger, cache de processo).
- Você precisa de controle estrito sobre variáveis globais que já existiriam de qualquer jeito.
- Você só quer “acessar de qualquer lugar” — prefira injeção de dependência.
- O objeto tem estado mutável relevante para o negócio (pesadelo em testes e concorrência).
- Você está numa aplicação multi-tenant ou serverless onde “único por processo” é a granularidade errada.
Relações com outros padrões
- Abstract Factory
- Fábricas e Directors costumam ser Singletons.
- Facade
- Uma Facade normalmente basta como Singleton.
- Flyweight
- Ambos economizam instâncias; Flyweight tem MUITAS instâncias imutáveis, Singleton tem UMA mutável.
- Prototype
- Quando o que você quer é um objeto pré-configurado (e não único), clonar um protótipo costuma ser melhor. Fora do catálogo GoF, a alternativa moderna é injeção de dependência com escopo singleton no container.
Verificação
Qual é a crítica mais forte ao Singleton?
- Ele acopla o código a um estado global e esconde dependências, prejudicando testes
- Ele consome mais memória que criar várias instâncias
- Ele não funciona em linguagens orientadas a objetos modernas
- Ele impede o uso de herança em qualquer parte do sistema
O custo real não é memória, é design: quem chama `getInstance()` não declara essa dependência na assinatura, e o estado global compartilhado torna testes frágeis. Injeção de dependência costuma ser a resposta melhor.