Singleton: o padrão mais famoso e mais mal usado

Singleton: o padrão mais famoso e mais mal usado

Robson Rabelo - 15 de julho de 2026 - 0 visualizações

Unicidade é boa; acesso global é o problema. Os casos legítimos, os pecados do clássico e a versão madura que os sêniores usam: único na raiz, injetado no resto.

Esta série percorre os padrões de projeto do catálogo clássico do GoF (Design Patterns, Gamma, Helm, Johnson e Vlissides, 1994) com uma promessa: zero culto, só uso real. E nada melhor para abrir do que o padrão que todo mundo conhece, muita gente usa, e a maioria usa errado: o Singleton.

O que ele promete

Garantir que uma classe tenha uma única instância, com acesso global a ela:

class Configuracao {
  private static instancia: Configuracao;
  private constructor() { /* carrega uma vez */ }

  static getInstance(): Configuracao {
    if (!Configuracao.instancia) {
      Configuracao.instancia = new Configuracao();
    }
    return Configuracao.instancia;
  }
}

// De qualquer lugar do código:
const config = Configuracao.getInstance();

Os casos legítimos existem e são reais: recursos caros e naturalmente únicos: o pool de conexões do banco, o client HTTP configurado, a conexão com o broker, o logger, o cache em memória do processo. Criar dez pools de conexão por descuido é bug caro; a unicidade protege.

Por que virou vilão

O problema nunca foi a unicidade; é o acesso global que vem de brinde:

1. Dependências invisíveis. Quando qualquer função pode chamar getInstance(), a assinatura mente: calcularFrete(pedido) parece pura, mas por dentro consulta configuração global, logger global, cache global. O acoplamento existe, só não está documentado onde deveria.

2. Testes pagam a conta. O singleton carrega estado entre testes: o teste 14 passa sozinho e falha depois do teste 9, o flake clássico. E mockar um getInstance() estático exige ginástica que uma dependência injetada dispensaria.

3. Concorrência e ciclo de vida. Em plataformas multi-thread, o getInstance() ingênuo tem corrida na primeira criação. E no cluster, cada processo tem o "seu" singleton: quem assumiu unicidade de verdade (contadores, locks) descobre em produção que ela era por processo.

Singleton: o clássico e a versão madura

A versão madura: único na raiz, injetado no resto

A evolução que os times experientes adotam separa as duas metades do padrão: mantenha a instância única, abandone o acesso global.

// composição da aplicação (a "raiz")
const config = carregarConfiguracao();        // criado UMA vez
const db = criarPoolDeConexoes(config);       // único, caro, compartilhado
const logger = criarLogger(config);

const repoPedidos = new RepositorioDePedidos(db, logger);   // recebe, não busca
const confirmarPedido = new ConfirmarPedido(repoPedidos);

A instância continua sendo uma só, criada na inicialização e passada como dependência a quem precisa. As assinaturas voltam a dizer a verdade, os testes recebem dublês sem acrobacia, e o ciclo de vida fica explícito. Frameworks com injeção de dependência (NestJS, Spring, Angular) fazem exatamente isso quando declaram um provider como singleton: unicidade gerenciada pelo contêiner, acesso por injeção.

Curiosidade do ecossistema: em Node.js, o cache de módulos já entrega "instância única por processo" de graça: exportar um objeto de um módulo é o singleton idiomático da plataforma, com os mesmos cuidados de estado global valendo.

A régua de bolso

  • Use unicidade para recursos caros/naturalmente únicos (pool, client, logger, cache local).
  • Evite o acesso global: crie na raiz, injete no resto.
  • Nunca use singleton como armário de estado mutável do domínio ("o carrinho atual", "o usuário logado"): isso é variável global com diploma, e o estado compartilhado tem lugares certos.
  • Desconfie de qualquer getInstance() espalhado pelo domínio: é o cheiro de acoplamento escondido.

Nos próximos artigos da série: Decorator, Proxy, Observer, Adapter e Factory Method, sempre com a mesma pergunta: que problema real esse padrão resolve, e quando ele é só cerimônia? É o olhar que aplicamos ao revisar código no serviço de Arquitetura de Software.

Quantos getInstance() tem o seu domínio? Faça o grep e conte para a IA da Rabelo Digital, aqui no canto da tela: ela mostra o caminho da injeção. Sem formulário, sem espera.


Leia também

Compartilhar:

Deixe um Comentário

Categorias

Posts Recentes