Singletons e static: perigo a vista

Este post no guj trouxe uma discussão já conhecida de volta a ativa: singleton. Devemos usar singletons ou métodos estáticos?

O Carlos Villela já coloca uma opinião muito interessante:

Estado mantido de forma estática numa aplicação é tão venenoso quanto variáveis globais. Não importa como esse estado é acessado. Seja via singletons ou métodos estáticos, vai continuar sendo venenoso.

Mais para frente, ele ainda diz:

Singletons é um indício de que você precisa pensar melhor sua arquitetura

Muitas pessoas (inclusive eu) consideram o Carlos Villela um extremista da orientação a objeto. Mas nesse tópico eu concordo totalmente com ele: estamos viciados em usar Singletons apenas para facilitar nossa busca por uma varáivel global (no caso de OO, uma referência a um objeto que é compartilhado globalmente). Quando que realmente faz sentido existir um e apenas um objeto de determinado tipo? É raro.

Em outras palavras, você deve evitar ao máximo a utilização de métodos estáticos (que tem um sabor de função procedural) e nem singletons (com o sabor variável global). Como resolver essa nossa necessidade? Certamente com injeção de dependências. Algumas pessoas já classificam Singleton como um antipattern: uma má solução para o seu problema.

A idéia é que você tire a responsabilidade de fazer lookup de recursos da sua lógica de negócio, e que esse seu recurso (essa sua dependência) seja lhe dada (injeção de dependências, DI) por outra pessoa, invertendo assim os papéis (inversão de controle, IOC): você não mais busca por um recurso, esse recurso é dado a você!

Entendo que muitos dos leitores já estão cansados de usar essas técnicas, mas vale lembrar que elas são úteis também no nosso caso de Singletons. Tanto que você vai encontrar diversos tópicos por aí como este: Como refatorar Singleton para injeção de dependências.

Mais abaixo o Villela fala do interessante recurso que alguns linguagens consideradas mais puramente OO tem, que no Java seria equivalente ao seguinte trecho (apenas ficção):

Integer i = 5;
Integer raiz = i.squareRoot();

Imagine todas as classes wrappers terem todos os tipos imagiáveis de operações? Não só elas, mas também BigInteger e BigDecimal? Nesse caso ainda prefiro as funçõezinhas procedurais da java.lang.Math :).

26 Comentários

  1. Carlos Villela 15/08/2006 at 08:29 #

    Sobre as classes wrappers ter todo tipo de operacao: funciona bem pra Smalltalk, Ruby, Io e diversas outras linguagens. O que todas essas tem em comum? “Classes” abertas: voce pode adicionar novos metodos a classes (ou prototipos) ja existentes.

    Assim da pra fazer coisas como o 9.days.ago do Rails, ou o 3/2 -> 3/2 do mathn. 😉

  2. Urubatan 15/08/2006 at 12:14 #

    Quanto aos singletons …
    Acho que varia bastante, não tem como tomar isto como verdade absoluta 😀
    também é possivel olhar pelo lado contrário, por exemplo …
    Faz sentido instanciar esta classe a todo momento?
    por exemplo um DAO, que é completamente Stateless.
    eu posso utilizar a mesma instancia para toda a minha aplicação, em diversos threads que não terei problema nenhum.
    Tudo bem, um Dao não é o exemplo mais orientado a objetos do mundo …
    Mas existem diversos outros serviços dentro da aplicação que não faz sentido criar instancias a todo momento.
    normalmente uso apenas DI para injetar a mesma instancia em todos os pontos necessários, mas não vejo razão para o container criar uma nova instancia destes serviços sempre que eu precisar deles …
    Até por que isto daria mais trabalho desnecessário para o Garbage Collector 😀
    Bom, esta é só a minha opinião 😀

  3. Urubatan 15/08/2006 at 12:15 #

    Mais uma coisa …
    Não vejo muita diferença de um singleton implementado manualmente (com um getInstance estático por exemplo)
    para um criado por um container de DI
    Nos dois casos vai haver apenas uma instancia daquela classe na aplicação 😀

  4. peas 15/08/2006 at 12:20 #

    Urubatan, a questão é que quem daria o new seria o Container, e ele vai dar um new só. O dia que você não quiser mais que aquele bean seja como um singleton, isso é, o dia que quiser mudar a política de instanciação daquele objeto, não precisará fazer mudanças estruturais no código dele (abrir o construtor, remover a referência estática para ele mesmo, remover o getInstance, etc).

    E o dia que seu DAO não for stateless? Os meus DAOs por exemplo não são: o HibernateDAO recebe Session no construtor.

    Eu entendo que o efeito final é o mesmo, porém evitar o Singleton te facilita as futuras modificações (e não é isso que queremos com OO?).

  5. Urubatan 16/08/2006 at 01:08 #

    verdade …
    pensando desta forma não da na mesma o DI e o singleton hardcoded mesmo 😀

  6. Carlos Villela 17/08/2006 at 08:31 #

    Outro otimo motivo pra nao usar singletons: tenta escrever um singleton com TDD. 😉

  7. George Gastaldi 21/08/2006 at 22:58 #

    Excelente Post ! Realmente a DI é muito melhor que Singleton. Eu conseguia ver isso de uma forma turva, mas depois desse post tudo ficou mais claro ! 😀

  8. George Gastaldi 21/08/2006 at 23:03 #

    Um comentário, me corrijam se eu estiver errado:
    “Não existe um mecanismo de injeção de dependência que não seja um Singleton, ou seja, para alcançar o propósito de um mecanismo de injeção de dependência, o próprio mecanismo deve ser um Singleton.”

    Certo ? Errado ? Opinem.

  9. Paulo Silveira 22/08/2006 at 18:05 #

    George, talvez você tenha razão quanto a isso, pois temos um problema ovo-galinha… Por exemplo, se fizermos nossa injeção de dependências em um Servlet Filter, deve haver alguém que controla esses filtros, que pode vir a ser um Singleton dentro do tomcat.

    Mas o interessante é que você ficou livre disso.

  10. Rafael Naufal 19/10/2006 at 10:33 #

    Para quem quiser entender um pouco mais de injeção de dependências, um modo de inversão de controle, vale a pena dar uma olhada neste artigo de Martin Fowler: Fowler IOC. Inclusive ele faz comparações da obtenção de recursos via um lookup com JNDI, utilizando ServiceLocator(que seria um Singleton) e o paradigma de inversão de controle.

  11. Marcelo Daniel 29/01/2009 at 01:56 #

    Eu concordo com o Urubatan, no final das contas eu acredito que tudo depende da necessidade. Também acho Singleton uma espécie de variável global (na verdade instância global). Acho radicalismo demais rotular singleton como anti pattern.

  12. Marcelo F Andrade 29/03/2012 at 13:31 #

    Em termos práticos, um revés de se usar métodos estáticos extensivamente é lembrar que não há herança dos mesmos. Portanto, se um dia você pensar em dividir a responsabilidade por aquele monte de métodos estáticos em mais de uma classe, vai ter um trabalho a mais do que se já tivesse os escrito como métodos de classe originalmente.

  13. André Valenti 20/09/2013 at 22:58 #

    Por muito tempo, não entendi o porquê do padrão singleton. Pra mim, era uma espécie de preguiça de escrever static na frente de todos os métodos da classe :).

    Hoje, penso como o Paulo Silveira: nada garante que o método sem estado de hoje continuará sem estado amanhã, e esse é o grande motivo para se fugir dos métodos estáticos.

    Isso motiva a importância de a injeção de dependência ser realmente muito fácil e transparente de se usar. O Guice (https://code.google.com/p/google-guice/) me pareceu a melhor alternativa para Java. Gostaria muito de ver algo parecido em JavaScript!

  14. Paulo Silveira 23/09/2013 at 18:50 #

    Exatamente Andre!

    Sobre fazer em JavaScript, quem manja de linguagens dinamicas diz que o conceito de injecao nao funciona tao bem e nao ajudaria muito. mas foge do meu conhecimento.

  15. Jonas Schumacher 11/09/2015 at 17:18 #

    E no caso do null object pattern? Não existe motivo para criação de várias classes, dependendo do caso pode até impactar negativamente na performance. Portanto, o singleton serviria bem, não?

Deixe uma resposta