Por que usar um singleton em vez de métodos estáticos?

92

Nunca encontrei boas respostas para essas perguntas simples sobre classes auxiliares / utilitários:

Por que eu criaria um singleton (sem estado) em vez de usar métodos estáticos?

Por que uma instância de objeto seria necessária se um objeto não tem estado?

Sebastien Lorber
fonte
possível duplicata de stackoverflow.com/questions/720744/static-class-and-singleton
Michael Borgwardt
Não pense que já falamos de 2 idiomas diferentes, então a resposta pode variar, mas obrigado pelo link, em java nunca ouvi o termo "monoestado"
Sebastien Lorber

Respostas:

79

Freqüentemente, singletons são usados ​​para introduzir algum tipo de estado global em um aplicativo. (Mais frequentemente do que o necessário, para ser honesto, mas isso é assunto para outra hora).

No entanto, existem alguns casos em que até mesmo um singleton sem estado pode ser útil:

  • Você espera estendê-lo com o estado em um futuro próximo.
  • Você precisa de uma instância de objeto por algum motivo técnico específico .
    Exemplo: objetos de sincronização para a instrução C # lockou Java synchronized.
  • Você precisa de herança, ou seja, deseja substituir facilmente seu singleton por outro usando a mesma interface, mas com uma implementação diferente.
    Exemplo: O Toolkit.getDefaultToolkit()método em Java retornará um singleton cujo tipo exato é dependente do sistema.
  • Você deseja igualdade de referência para um valor sentinela .
    Exemplo: DBNull.Valueem C #.
Heinzi
fonte
27
Eu vou com +1, embora singletons IMHO sejam mal utilizados para introduzir estados globais. O propósito de um singleton não é tornar um objeto globalmente disponível, mas fazer com que um objeto seja instanciado apenas uma vez. Os objetos globais são um mal necessário. A menos que seja realmente necessário, deve-se tentar não usá-los, pois geralmente levam a um alto acoplamento, com SomeSingleton.getInstance (). SomeMethod () em todos os lugares. :)
back2dos
Pode ser útil em jogos em que você deseja apenas uma instância de renderização em vez de várias instâncias de renderização, ou com uma classe de tubulação de rede onde você configura um canal seguro que pode haver apenas uma conexão por vez.
Tschallacka
2
"Substitua facilmente o seu singleton" parte é o ponto mais importante do meu ponto de vista. Rest está muito próximo da implementação de uma classe estática.
Teoman shipahi
1
Singletons são valores sentinela não nulos úteis para tipos de soma / produto e semelhantes. Por exemplo, sendo o valor Nenhum / Nada em um tipo Opção ou o valor Vazio para um tipo de coleção. Você obtém testes rápidos Nenhum / Vazio como um bônus, porque a igualdade de referência é tudo o que é necessário.
itsbruce
@itsbruce: Seus exemplos não são singletons : a lista vazia não é a única instância possível da classe List, e o valor None não é a única instância possível da classe Option. No entanto, há exemplos em que os valores de sentinela são singletons, e tomei a liberdade de adicionar um à minha resposta. Obrigado pela entrada!
Heinzi
37

Eu poderia ver um caso para um singleton sem estado sendo usado em vez de uma classe de métodos estáticos, ou seja, para injeção de dependência .

Se você tem uma classe auxiliar de funções de utilitário que está usando diretamente, ela cria uma dependência oculta; você não tem controle sobre quem pode usá-lo ou onde. Injetar a mesma classe auxiliar por meio de uma instância singleton sem estado permite que você controle onde e como ela está sendo usada e substitua / simule / etc. quando for necessário.

Torná-lo uma instância singleton simplesmente garante que você não está alocando mais objetos do tipo do que o necessário (já que você só precisa de um).

tzaman
fonte
1
"você não tem controle sobre quem pode usá-lo ou onde." Por que alguém precisaria disso?
hagrawal
1
@hagrawal para fins de teste, você deve ser capaz de zombar
Jemshit Iskenderov
15

Na verdade, encontrei outra resposta não mencionada aqui: os métodos estáticos são mais difíceis de testar.

Parece que a maioria dos frameworks de teste funcionam muito bem para simular métodos de instância, mas muitos deles não lidam de maneira decente com a simulação de métodos estáticos.

Sebastien Lorber
fonte
2
Mas Powermock parece ser capaz de fazer isso
Sebastien Lorber
6

Na maioria das linguagens de programação, as classes fogem muito do sistema de tipos. Embora uma classe, com seus métodos e variáveis ​​estáticos, seja um objeto, muitas vezes ela não pode implementar uma interface ou estender outras classes. Por esse motivo, não pode ser usado de forma polimórfica, pois não pode ser o subtipo de outro tipo. Por exemplo, se você tiver uma interface IFooable, que é exigida por várias assinaturas de método de outras classes, o objeto de classe StaticFoonão pode ser usado no lugar de IFooable, ao passo que FooSingleton.getInstance()pode (assumindo, FooSingletonimplementa IFooable).

Observe que, como comentei na resposta de Heinzi, um singleton é um padrão para controlar a instanciação. Ele substitui new Class()por Class.getInstance(), o que dá ao autor Classmais controle sobre as instâncias, que ele pode usar para evitar a criação de instâncias desnecessárias. O singleton é apenas um caso muito especial do padrão de fábrica e deve ser tratado como tal. O uso comum torna-o mais o caso especial de registros globais, que muitas vezes acabam mal, porque os registros globais não devem ser usados ​​à toa.

Se você planeja fornecer funções auxiliares globais, os métodos estáticos funcionarão bem. A classe não atuará como classe, mas apenas como um namespace. Eu sugiro que você preserve a alta coesão ou pode acabar com os problemas de acoplamento mais estranhos.

greetz
back2dos

back2dos
fonte
4

Há uma compensação entre usar qual. Singletons podem ou não ter estado e se referem a objetos. Se eles não estiverem mantendo o estado e forem usados ​​apenas para acesso global, então estático é melhor, pois esses métodos serão mais rápidos. Mas se você deseja utilizar objetos e conceitos OOP (polimorfismo de herança), então singleton é melhor.

Considere um exemplo: java.lang.Runtime é uma classe singleton em java. Esta classe permite diferentes implementações para cada JVM. A implementação é única por JVM. Se essa classe fosse estática, não podemos passar diferentes implementações baseadas em JVM.

Achei este link muito útil: http://javarevisited.blogspot.com/2013/03/difference-between-singleton-pattern-vs-static-class-java.html ?

Espero que ajude!!

Atihska
fonte
Essa resposta é boa para incluir um exemplo concreto no mundo real.
systemovich
2

Para mim, "Want Object State use Singleton, Want Function usa método estático"

Depende do que você quer. Sempre que você quiser o estado do objeto (por exemplo, polimorfismo como estado nulo em vez de null, ou estado padrão), singleton é a escolha apropriada para você, enquanto o método estático usa quando você precisa de função (receba entradas e retorne uma saída).

Eu recomendo para o caso singleton, ele deve ser sempre o mesmo estado após ser instanciado. Não deve ser clonável nem receber qualquer valor para definir (exceto configuração estática do arquivo, por exemplo , arquivo de propriedades em java).

PS O desempenho entre esses 2 é diferente em milissegundos, então concentre-se primeiro na Arquitetura .

Toomtarm Kung
fonte
1

Singleton não é sem estado, ele mantém o estado global.

Algumas razões pelas quais posso pensar em usar Singleton são:

  • Para evitar vazamentos de memória
  • Para fornecer o mesmo estado para todos os módulos em um aplicativo, por exemplo, conexão de banco de dados
Indigo Praveen
fonte
Eu sei, mas na verdade um singleton pode ser mais ou menos sem estado ... Se ele não compartilhar nenhum atributo de classe ...
Sebastien Lorber