Aprenda o pattern Singleton na teoria e na prática

Nesse artigo será abordado de forma detalhada e prática o Design Pattern Creational (Padrão de Projeto Criacional) Singleton. Afinal, quando devo ou não usá-lo? De fato é um anti-pattern?

Conceito

O Singleton é um Padrão de Projeto Criacional onde uma classe terá uma única instância, tendo um ponto de acesso global a essa instância.

Figura do Diagrama de classe (UML) do padrão Singleton

Perceba que no diagrama acima o atributo "instancia" é estático e o tipo dele é a própria classe. Ele será o "controle" para garantir somente uma única instância. Observe que o método construtor "Singleton()" é PRIVADO. Logo não será possível instanciar essa classe a não ser que seja feito através do método estático "GetInstancia()". Portanto, todas classes poderão acessar essa classe sem precisar instanciá-la.

Exemplo - Singleton

Veja abaixo um exemplo de implementação do Singleton em C#.

// Para instanciar a classe:
// Singleton singleton = Singleton.getInstancia();

public class Singleton
{

    private static Singleton instancia = null;

    private Singleton() { }

    public static Singleton getInstancia()
    {
        if (null == instancia)
            instancia = new Singleton();

        return instancia;
    }

}

No exemplo ilustrativo veja que independente de quantas classes acessarem "Singleton", sempre terá apenas uma única instância. Além disso, resolve-se o problema de ficar armazenando em variáveis de ambiente aqueles objetos que sempre é necessário usar na aplicação.

🚨
Esse pattern viola o primeiro princípio do SOLID (Princípio da Responsabilidade Única - SRP). A classe passa a ter mais de uma responsabilidade (controle de threads + regras da própria classe. Para saber mais sobre SOLID, acesse o artigo clicando aqui.

E onde exatamente eu aplico na vida real?

O clássico exemplo de uso do design pattern Singleton é a conexão com o banco de dados. Se cada requisição instanciar um objeto que faz a conexão para o banco de dados, quanto tiver muitos acessos seu banco de dados provavelmente ficará indisponível. Quando você aplica Singleton, você garante que terá apenas uma única conexão que será usada independente do número de usuários.

Afinal, Singleton é um anti-pattern?

Antes de mais nada, um "anti-pattern" no conceito da Engenharia de Software são práticas que são consideradas ruins. Em um primeiro momento até pode parecer bom, mas conforme o projeto ganha proporções maiores, a prática adotada não foi uma boa escolha.

Para alguns Autores o Singleton quando usado de forma "indiscriminada" traz alguns problemas. São eles:

  1. Dificuldade para montar testes unitários independentes: Como o acesso é global, pode afetar outros testes;
  2. Alto nível de acoplamento: como o acesso é global, diversos trechos de código terão acesso a esse objeto;
  3. Problemas de concorrência: Em sistemas multithreaded, pode surgir o problema de "condições de corrida" que pode gerar erros imprevisíveis;
  4. Ocultação de Dependências: Apenas ter acesso ao objeto não causa clareza sobre o que de fato está ocorrendo. Então dificulta entender o relacionamento entre diversas partes do sistema.

Conclusão

Nos projetos de desenvolvimento não existe "certo" ou "errado", se ambos produzem o resultado esperado. Porém, pode-se desenvolver projetos que diminua o esforço em dar manutenção. Apesar do Singleton ter "prós" e "contras", cabe ao desenvolvedor definir se é bom ou não usar para aquela situação.