O que há de tão ruim nos singletons? [fechadas]


1983

O padrão Singleton é um membro totalmente integralizado da GoF 's padrões de livro , mas ultimamente parece bastante órfãs pelo mundo do desenvolvedor. Eu ainda uso muitos singletons, especialmente para as classes de fábrica , e embora você precise ter um pouco de cuidado com os problemas de multithreading (como qualquer classe, na verdade), não vejo por que eles são tão terríveis.

O Stack Overflow parece supor que todos concordam que os Singletons são maus. Por quê?

Apoie suas respostas com " fatos, referências ou conhecimentos específicos "


6
Devo dizer que o uso de um design singleton me queimou recentemente, pois tentei adaptar o código. Como faço isso no meu tempo livre, estou com preguiça de refatorar isso. Más notícias para produtividade.
Marcin

71
Há um monte de 'contras' nas respostas, mas eu também gostaria de ver alguns bons exemplos de quando o padrão é bom, para contraste com o mau ...
DGM

50
Escrevi um post sobre o assunto há alguns meses: jalf.dk/blog/2010/03/… - e deixe-me dizer isso de uma vez. Pessoalmente, não consigo pensar em uma única situação em que um singleton seja a solução certa. Isso não significa que essa situação não exista, mas ... chamá-los de raros é um eufemismo.
jalf

8
@ AdamSmith, isso não significa que você precisa , mas significa que você pode acessá-lo assim. E se você não pretende acessá-lo assim, há poucas razões para torná-lo um singleton em primeiro lugar. Portanto, seu argumento é efetivamente "não há mal nenhum em fazer um singleton se não o tratarmos como um singleton. Sim, ótimo. Meu carro também não polui se eu não dirigir nele. Mas é mais fácil não adquirir um carro no primeiro lugar;) (divulgação completa: Eu realmente não têm um carro).
jalf

35
A pior parte deste tópico é que as pessoas que odeiam singletons raramente dão sugestões concretas sobre o que usar. Os links para artigos de periódicos e blogs auto-publicados em todo este artigo da SO, por exemplo, continuam falando sobre o porquê de não usar singletons (e são todos excelentes motivos), mas são extremamente escassos em substituições. Muitas ondas de mão, no entanto. Aqueles de nós que tentam ensinar aos novos programadores por que não usar singletons não têm muitos bons exemplos de terceiros para apontar, apenas exemplos inventados. É cansativo.
Ti Strga

Respostas:


1294

Parafraseado de Brian Button:

  1. Eles geralmente são usados ​​como uma instância global, por que isso é tão ruim? Porque você oculta as dependências do seu aplicativo no seu código, em vez de expô-las através das interfaces. Tornar algo global para evitar distribuir é um cheiro de código .

  2. Eles violam o princípio da responsabilidade única : em virtude de controlarem sua própria criação e ciclo de vida.

  3. Eles inerentemente fazem com que o código seja fortemente acoplado . Isso dificulta a falsificação deles em teste em muitos casos.

  4. Eles carregam o estado durante toda a vida útil do aplicativo. Outro sucesso nos testes, pois você pode acabar com uma situação em que os testes precisam ser solicitados, o que é um grande não para testes de unidade. Por quê? Porque cada teste de unidade deve ser independente do outro.


324
Eu discordo de você. Como os comentários são permitidos apenas 600 caracteres, eu escrevi uma postagem no blog para comentar sobre isso, consulte o link abaixo. jorudolph.wordpress.com/2009/11/22/singleton-considerations #
Johannes Rudolph

61
Nos pontos 1 e 4, acho que os singletons são úteis e, na verdade, quase perfeitos para armazenar dados em cache (especialmente de um banco de dados). O aumento no desempenho está muito além das complexidades envolvidas nos testes de unidade de modelagem.
Dai Bok

56
@Dai Bok: "cache de dados (especialmente a partir de um DB)" usar o padrão de proxy para fazer isso ...
paxos1977

55
Uau, ótimas respostas. Provavelmente eu usei palavras muito agressivas aqui, por isso, lembre-se de que estava respondendo a uma pergunta negativa. Minha resposta foi feita para ser uma pequena lista dos 'anti-padrões' que ocorrem devido ao mau uso de Singleton. Transparência completa; Eu também uso Singletons de tempos em tempos. Existem perguntas mais neutras sobre SO que seriam excelentes fóruns para quando os Singletons possam ser considerados uma boa idéia. Por exemplo, stackoverflow.com/questions/228164/…
Jim Burger

21
Eles não são ótimos para armazenar em cache em um ambiente multithread. Você pode facilmente derrotar um cache com vários threads lutando por um recurso limitado. [mantida por um Singleton]
monksy

449

Singletons resolvem um (e apenas um) problema.

Contenção de Recursos.

Se você tem algum recurso que

( 1 ) pode ter apenas uma instância e

( 2 ) você precisa gerenciar essa instância única,

você precisa de um singleton .

Não há muitos exemplos. Um arquivo de log é o grande. Você não deseja simplesmente abandonar um único arquivo de log. Você deseja liberar, sincronizar e fechá-lo corretamente. Este é um exemplo de um único recurso compartilhado que precisa ser gerenciado.

É raro você precisar de um singleton. A razão pela qual eles são ruins é que se sentem globais e são membros totalmente pagos do livro GoF Design Patterns .

Quando você pensa que precisa de um ambiente global, provavelmente está cometendo um terrível erro de design.


43
O hardware também é um exemplo, certo? Os sistemas embarcados possuem muito hardware que pode usar singletons - ou talvez um grande? <grin>
Jeff

170
Concordo plenamente. Há muita conversa determinada "essa prática é ruim" flutuando sem qualquer reconhecimento de que a prática possa ter seu lugar. Muitas vezes, a prática é apenas "ruim" porque é frequentemente mal utilizada. Não há nada inerentemente errado com o padrão Singleton, desde que seja aplicado adequadamente.
Damovisa

53
Singletons reais por princípio são muito raros (e uma fila de impressoras certamente não é uma, nem um arquivo de log - consulte log4j). Na maioria das vezes, o hardware é um singleton por coincidência e não por princípio. Todo o hardware conectado a um PC é, na melhor das hipóteses, um singleton coincidente (pense em vários monitores, mouses, impressoras, placas de som). Mesmo um detector de partículas de 500 milhões de dólares é um singleton por coincidência e restrições orçamentárias - que não se aplicam ao software, portanto: sem singleton. Nas telecomunicações, nem o número de telefone nem o telefone físico são singletons (pense em ISDN, call center).
Digitalrbeiter

23
O hardware pode ter apenas uma instância de uma variedade de recursos, mas o hardware não é um software. Não há razão para que uma única porta serial em uma placa de desenvolvimento seja modelada como um Singleton. De fato, modelá-lo apenas tornará mais difícil portar para a nova placa que possui duas portas!
traço-tom-bang

19
Então você escreveria duas classes idênticas, duplicando muito código, apenas para ter dois singletons representando duas portas? Que tal usar apenas dois objetos globais SerialPort? Que tal não modelar o hardware como classes? E por que você usaria singletons, o que também implica acesso global? Deseja que todas as funções do seu código possam acessar a porta serial?
jalf

352

Alguns esnobes de codificação os consideram apenas um global glorificado. Da mesma forma que muitas pessoas odeiam a declaração goto , há outras que odeiam a idéia de usar um global . Eu já vi vários desenvolvedores se esforçarem extraordinariamente para evitar uma globalização porque consideravam usar uma como uma admissão de falha. Estranho mas verdade.

Na prática, o padrão Singleton é apenas uma técnica de programação que é uma parte útil do seu conjunto de conceitos. De tempos em tempos, você pode achar que é a solução ideal e, portanto, usá-lo. Mas usá-lo apenas para que você possa se gabar de usar um padrão de design é tão estúpido quanto se recusar a usá-lo, porque é apenas global .


17
O fracasso que vejo em Singleton é que as pessoas as usam em vez de globais porque são de alguma forma "melhores". O problema é (a meu ver), que as coisas que Singleton traz para a mesa nesses casos são irrelevantes. (Construct-on-primeiro-uso é trivial para implementar de forma não-singleton, por exemplo, mesmo se ele não está realmente usando o construtor de fazê-lo.)
traço-tom-bang

21
A razão pela qual "nós" os desprezamos é que "nós" freqüentemente os vemos usados ​​de maneira errada e com muita frequência. "Nós" sabemos que eles têm seu lugar de causa.
Bjarke Freund-Hansen

5
@ Phil, você declarou "de tempos em tempos você pode achar que é a solução ideal e, portanto, usá-la". Ok, então exatamente em que caso acharíamos um singleton útil?
Pacerier

22
@Pacerier, sempre que todas as seguintes condições forem válidas: (1) você precisa apenas de algo, (2) precisa passar essa coisa como argumento em um grande número de chamadas de método, (3) você está disposto a aceitar um a chance de ter que refatorar um dia em troca de uma redução imediata no tamanho e na complexidade do seu código, não passando a porcaria por toda parte.
Antinome

18
Não acho que isso responda nada, apenas diz que 'às vezes pode caber, outras vezes não'. OK, mas por que e quando? O que torna essa resposta mais do que um argumento para moderação ?
Guildenstern

219

Misko Hevery, do Google, tem alguns artigos interessantes sobre exatamente esse tópico ...

Singletons são mentirosos patológicos tem um exemplo de teste de unidade que ilustra como os singletons podem dificultar descobrir cadeias de dependência e iniciar ou testar um aplicativo. É um exemplo bastante extremo de abuso, mas o argumento que ele faz ainda é válido:

Singletons nada mais são do que um estado global. O estado global permite que seus objetos possam se apossar secretamente de coisas que não são declaradas em suas APIs e, como resultado, os Singletons transformam suas APIs em mentirosas patológicas.

Onde estão todos os Singletons Gone afirma que a injeção de dependência facilitou a obtenção de instâncias para os construtores que os exigem, o que alivia a necessidade subjacente por trás dos Singletons ruins e globais que foram criticados no primeiro artigo.


8
Os artigos de Misko sobre o assunto são a melhor coisa no momento.
283 Chris Mayer

22
O primeiro link, na verdade, não resolve um problema com singletons, mas assume uma dependência estática dentro da classe. É possível corrigir o exemplo dado passando parâmetros, mas ainda usando singletons.
DGM

17
@DGM: Exatamente - de fato, há uma enorme desconexão lógica entre a parte 'racional' do artigo e a parte 'Singletons é a causa'.
Harper Shelby

1
O artigo CreditCard de Misko é um exemplo extremo de uso indevido desse padrão.
25412 Alex

2
Lendo o segundo artigo Na verdade, os singletons fazem parte do modelo de objeto descrito. No entanto, em vez de serem acessíveis globalmente, eles são privados para os objetos Factory.
FruitBreak

121

Eu acho que a confusão é causada pelo fato de as pessoas não conhecerem a aplicação real do padrão Singleton. Não posso enfatizar isso o suficiente. Singleton não é um padrão para envolver os globais. O padrão Singleton deve ser usado apenas para garantir que uma e apenas uma instância de uma determinada classe exista durante o tempo de execução.

As pessoas pensam que Singleton é mau porque o estão usando para globais. É por causa dessa confusão que Singleton é menosprezado. Por favor, não confunda Singletons e Globais. Se usado para a finalidade a que se destina, você obterá benefícios extremos com o padrão Singleton.


20
Qual é essa instância, disponível em todo o aplicativo? Oh. Global . "Singleton não é um padrão para envolver os globais" é ingênuo ou enganoso, pois, por definição , o padrão envolve uma classe em torno de uma instância global.
cHao

26
É claro que você pode criar uma instância da classe quando o aplicativo iniciar e injetar essa instância, por meio de uma interface, em qualquer coisa que a utilize. A implementação não deve se importar com a possibilidade de haver apenas uma.
31180 Scott Scullock

4
@ Dainius: Realmente não há, no final. Claro, você não pode substituir arbitrariamente a instância por outra. (Exceto naqueles momentos de indução de facepalm quando você o faz . Na verdade, já vi setInstancemétodos antes.) Mas isso pouco importa - o fato de que "precisamos" de um singleton também não sabia nada sobre encapsulamento ou o que há de errado com isso. estado global mutável, de modo que ele (?) forneceu prestadores de serviço para todos. solteiro. campo. (E sim, isso acontece. Monte Quase todas as Singleton que eu já vi na natureza era mutável por design, e muitas vezes embarassingly lo..)
Chao

4
@ Dainius: Em grande medida, nós já temos. "Preferir composição sobre herança" já é algo já faz um bom tempo. Quando a herança é comprovadamente a melhor solução, é claro que você é livre para usá-la. A mesma coisa acontece com singletons, globals, threading gotoetc. Eles podem funcionar em muitos casos, mas, francamente, "funciona" não é suficiente - se você quiser ir contra a sabedoria convencional, é melhor demonstrar como sua abordagem é melhor que as soluções convencionais. E ainda não vi esse caso para o padrão Singleton.
cHao

3
Para que não falemos um do outro, não estou falando apenas de uma instância disponível globalmente. Existem muitos casos para isso. O que estou falando (particularmente quando digo "capital-S Singleton") é o padrão Singleton do GoF, que incorpora essa instância global única na própria classe, a expõe por meio de um getInstancemétodo ou nome semelhante e evita a existência de um segunda instância. Francamente, nesse ponto, você pode nem ter a única instância.
cHao

72

Uma coisa bastante ruim sobre singletons é que você não pode estendê-los com muita facilidade. Você basicamente precisa criar algum tipo de padrão decorador ou algo assim, se quiser mudar o comportamento deles. Além disso, se um dia você quiser ter várias maneiras de fazer isso, pode ser um pouco doloroso mudar, dependendo de como você define seu código.

Uma coisa a observar, se você usar singletons, tente passá-los para quem precisar deles, em vez de acessá-los diretamente ... Caso contrário, se você optar por ter várias maneiras de fazer o que o singleton faz, será bastante difícil de mudar, pois cada classe incorpora uma dependência se acessar o singleton diretamente.

Então, basicamente:

public MyConstructor(Singleton singleton) {
    this.singleton = singleton;
}

ao invés de:

public MyConstructor() {
    this.singleton = Singleton.getInstance();
}

Eu acredito que esse tipo de padrão é chamado injeção de dependência e geralmente é considerado uma coisa boa.

Porém, como qualquer padrão ... Pense sobre isso e considere se o seu uso na situação fornecida é inadequado ou não ... Normalmente, as regras são quebradas e os padrões não devem ser aplicados à toa, sem pensar.


17
Heh, se você fizer isso em todos os lugares, terá que passar uma referência ao singelton em todos os lugares também e, portanto, não terá mais um singleton. :) (que geralmente é uma coisa boa IMO.)
Bjarke Freund-Hansen

2
@ BjarkeFreund-Hansen - Bobagem, o que você está falando? Um singleton é simplesmente uma instância de uma classe que é instatada uma vez. Referenciar um Singleton não copia o objeto real, apenas o referencia - você ainda tem o mesmo objeto (leia-se: Singleton).
M. Mimpen

2
@ M.Mimpen: Não, um Singleton maiúsculo-S (que é o que está sendo discutido aqui) é uma instância de uma classe que (a) garante que apenas uma instância existirá e (b) é acessada por meio da própria classe ponto de acesso global incorporado. Se você declarou que nada deveria chamar getInstance(), então (b) não é mais verdade.
cHao 17/02/2014

2
@cHao Eu não sigo você ou você não entende a quem eu comento - o que é Bjarke Freund-Hansen. Bjarke afirma que ter várias referências de um singleton resulta em vários singletons. Isso certamente não é verdade, pois não há cópias em profundidade.
M. Mimpen 17/02

6
@ M.Mimpen: Tomo o seu comentário para se referir mais ao efeito semântico. Depois de proibir a chamada getInstance(), você efetivamente descartou a única diferença útil entre o padrão Singleton e uma referência comum. No que diz respeito ao restante do código, a simplicidade não é mais uma propriedade. Somente o interlocutor getInstance()precisa saber ou se importar com quantas instâncias existem. Com apenas um chamador, custa mais esforço e flexibilidade para a classe impor de maneira confiável a singeleza do que fazer com que o chamador simplesmente armazene uma referência e reutilize-a.
cHao 17/02

69

O padrão singleton não é um problema em si. O problema é que o padrão é frequentemente usado por pessoas que desenvolvem software com ferramentas orientadas a objetos sem ter uma compreensão sólida dos conceitos de OO. Quando singletons são introduzidos nesse contexto, eles tendem a se transformar em classes incontroláveis ​​que contêm métodos auxiliares para pouco uso.

Singletons também são um problema de uma perspectiva de teste. Eles tendem a dificultar a escrita de testes de unidade isolados. Inversão de controle (IoC) e injeção de dependência são padrões destinados a superar esse problema de uma maneira orientada a objetos que se presta a testes de unidade.

Em um ambiente de coleta de lixo, os singletons podem se tornar rapidamente um problema em relação ao gerenciamento de memória.

Há também o cenário multithread em que singletons podem se tornar um gargalo e um problema de sincronização.


4
Eu sei que é fio de muitos anos. oi @Kimoz u disse: - singletons podem se tornar rapidamente um problema no gerenciamento de memória. gostaria de explicar com mais detalhes que tipo de problema pode surgir em relação à coleta de lixo e lixo simples.
Thomas

@ Kimoz, a pergunta está perguntando "Por que o padrão singleton não é um problema em si?" e você apenas repetiu o argumento, mas não forneceu nem um único caso de uso válido do padrão singleton.
Pacerier

@ Thomas, porque um singleton por definição existe em apenas uma instância. Portanto, geralmente é complexo atribuir a única referência a null. Isso pode ser feito, mas significa que você controla totalmente o ponto após o qual o singleton não é usado no seu aplicativo. E isso é raro, e geralmente o oposto do que os entusiastas de singleton estão procurando: uma maneira simples de tornar uma única instância sempre acessível. Em algumas estruturas de DI, como Guice ou Dagger, não é possível se livrar de um singleton e ele permanece para sempre na memória. (Embora os singletons fornecidos pelo contêiner sejam muito melhores que os caseiros).
Snicolas 28/05

54

Um singleton é implementado usando um método estático. Os métodos estáticos são evitados por pessoas que fazem testes de unidade porque eles não podem ser ridicularizados ou descartados. A maioria das pessoas neste site são grandes defensores dos testes de unidade. A convenção geralmente mais aceita para evitá-los é usar a inversão do padrão de controle .


9
Isso parece mais um problema com o teste de unidade que pode testar objetos (unidades), funções (unidades), bibliotecas inteiras (unidades), mas falha com qualquer coisa estática na classe (também unidades).
precisa saber é o seguinte

2
você não deve supor todas as referências externas? Se você é, então o que é um problema para o moc singleton, se não, você está realmente fazendo testes de unidade?
Dainius 24/10

@ Dainius: Zombar de instâncias é muito menos problemático do que zombar de classes. É possível extrair a classe em teste do restante do aplicativo e testar com uma Singletonclasse falsa . No entanto, isso complica imensamente o processo de teste. Por um lado, agora você precisa ser capaz de descarregar as classes à vontade (não é realmente uma opção na maioria dos idiomas) ou iniciar uma nova VM para cada teste (leia: os testes podem levar milhares de vezes mais). Para dois, no entanto, a dependência Singletoné um detalhe de implementação que agora está vazando em todos os seus testes.
cHao 11/01

Powermock pode zombar de coisas estáticas.
Snicolas 28/05

zombar de um objeto significa criar um objeto real? Se a imitação não cria um objeto real, por que importa se a classe é singleton ou o método é estático?
Arun Raaj

45

Singletons também são ruins quando se trata de clustering . Porque então, você não tem "exatamente um singleton" em seu aplicativo.

Considere a seguinte situação: Como desenvolvedor, você deve criar um aplicativo Web que acesse um banco de dados. Para garantir que as chamadas simultâneas ao banco de dados não entrem em conflito, crie um save de thread SingletonDao:

public class SingletonDao {
    // songleton's static variable and getInstance() method etc. omitted
    public void writeXYZ(...){
        synchronized(...){
            // some database writing operations...
        }
    }
}

Portanto, você tem certeza de que existe apenas um singleton no seu aplicativo e todo o banco de dados passa por esse e apenas SingletonDao. Seu ambiente de produção agora fica assim: Single Singleton

Está tudo bem até agora.

Agora, considere que você deseja configurar várias instâncias do seu aplicativo Web em um cluster. Agora, de repente, você tem algo parecido com isto:

Muitos singletons

Isso parece estranho, mas agora você tem muitos singletons em seu aplicativo . E é exatamente isso que um singleton não deve ser: ter muitos objetos dele. Isso é especialmente ruim se você, como mostrado neste exemplo, deseja fazer chamadas sincronizadas para um banco de dados.

Obviamente, este é um exemplo de mau uso de um singleton. Mas a mensagem deste exemplo é: Você não pode confiar que exista exatamente uma instância de um singleton em seu aplicativo - especialmente quando se trata de armazenamento em cluster.


4
se você não sabe como implementar o singleton, não deve fazer isso. Se você não sabe o que está fazendo, deve encontrá-lo primeiro e somente depois fazer o que precisa.
Dainius

3
Isso é interessante, eu tenho uma pergunta. Então, qual é exatamente o problema se singletons - cada um em uma máquina / JVM diferente - estão se conectando a um único banco de dados? O escopo de singletons é apenas para essa JVM específica e ainda é verdade mesmo em um cluster. Em vez de apenas dizer filosoficamente que essa situação em particular é ruim porque nossa intenção era um único objeto em todo o aplicativo, eu ficaria feliz em ver quaisquer problemas técnicos que possam surgir devido a esse arranjo.
Saurabh Patil

39
  1. É facilmente (ab) usado como uma variável global.
  2. Classes que dependem de singletons são relativamente mais difíceis de testar isoladamente.

33

O monopólio é o diabo e os singletons com estado não-readonly / mutável são o problema "real" ...

Depois de ler Singletons são Mentirosos Patológicos, como sugerido na resposta de Jason, me deparei com este pequeno trecho que fornece o melhor exemplo apresentado de como os singletons são frequentemente mal utilizados.

Global é ruim porque:

  • uma. Causa conflito no namespace
  • b. Expõe o estado de forma injustificada

Quando se trata de Singletons

  • uma. A maneira explícita de OO de chamá-los impede os conflitos, então aponte a. não é um problema
  • b. Singletons sem estado são (como fábricas) não são um problema. Singletons com estado podem novamente cair em duas categorias, aquelas que são imutáveis ​​ou gravam uma vez e leem muitas (arquivos de configuração / propriedade). Estes não são ruins. Singletons mutáveis, que são o tipo de referência, são os que você está falando.

Na última declaração, ele está se referindo ao conceito do blog de 'singletons são mentirosos'.

Como isso se aplica ao monopólio?

Para iniciar um jogo de monopólio, primeiro:

  • estabelecemos as regras primeiro para que todos estejam na mesma página
  • todos recebem um começo igual no início do jogo
  • apenas um conjunto de regras é apresentado para evitar confusão
  • as regras não podem mudar ao longo do jogo

Agora, para quem realmente não jogou monopólio, esses padrões são ideais na melhor das hipóteses. É difícil engolir uma derrota no monopólio, porque o monopólio é sobre dinheiro; se você perder, terá que observar cuidadosamente o resto dos jogadores terminar o jogo, e as perdas são geralmente rápidas e esmagadoras. Portanto, as regras geralmente são distorcidas em algum momento para servir aos interesses de alguns dos jogadores às custas dos outros.

Então você está jogando monopólio com os amigos Bob, Joe e Ed. Você está rapidamente construindo seu império e consumindo participação de mercado a uma taxa exponencial. Seus oponentes estão enfraquecendo e você começa a cheirar sangue (figurativamente). Seu amigo Bob investiu todo o seu dinheiro no engarrafamento do maior número possível de propriedades de baixo valor, mas ele não está recebendo um alto retorno sobre o investimento da maneira que ele esperava. Bob, como um golpe de má sorte, cai no seu calçadão e é retirado do jogo.

Agora, o jogo vai de dados amigáveis ​​a negócios sérios. Bob foi feito o exemplo do fracasso e Joe e Ed não querem acabar como 'aquele cara'. Então, sendo o principal jogador, você de repente se torna o inimigo. Joe e Ed começam a praticar operações sob a mesa, injeções de dinheiro pelas costas, troca de casas subvalorizada e geralmente qualquer coisa para enfraquecê-lo como jogador até que um deles chegue ao topo.

Então, em vez de um deles vencer, o processo começa tudo de novo. De repente, um conjunto finito de regras se torna um alvo em movimento e o jogo se degenera no tipo de interações sociais que constituiriam a base de todos os reality shows de TV de alta classificação desde o Survivor. Por que, porque as regras estão mudando e não há consenso sobre como / por que / o que eles devem representar e, mais importante, não há ninguém tomando as decisões. Todo jogador do jogo, nesse ponto, está fazendo suas próprias regras e caos, até que dois jogadores estejam cansados ​​demais para manter a farsa e desistir lentamente.

Portanto, se um livro de regras para um jogo representasse com precisão um singleton, o livro de regras do monopólio seria um exemplo de abuso.

Como isso se aplica à programação?

Além de todos os problemas óbvios de segurança de encadeamento e sincronização que os singletons mutáveis ​​apresentam ... Se você possui um conjunto de dados, ele pode ser lido / manipulado por várias fontes diferentes simultaneamente e existe durante a vida útil da execução do aplicativo, provavelmente é um bom momento para voltar atrás e perguntar "estou usando o tipo certo de estrutura de dados aqui".

Pessoalmente, eu vi um programador abusar de um singleton usando-o como uma espécie de armazenamento de banco de dados de threads cruzados dentro de um aplicativo. Tendo trabalhado diretamente no código, posso atestar que foi um processo lento (por causa de todos os bloqueios de thread necessários para torná-lo seguro) e um pesadelo para trabalhar (por causa da natureza imprevisível / intermitente dos erros de sincronização) e quase impossível testar em condições de 'produção'. Certamente, um sistema poderia ter sido desenvolvido usando pesquisa / sinalização para superar alguns dos problemas de desempenho, mas isso não resolveria os problemas com testes e por que se preocupar quando um banco de dados 'real' já pode realizar a mesma funcionalidade de uma maneira muito mais robusta / maneira escalável.

Um Singleton é apenas uma opção se você precisar do que um Singleton fornece. Uma instância de somente leitura de um objeto. Essa mesma regra deve cascata para as propriedades / membros do objeto também.


1
E se o singleton descontar alguns dados?
Yola

@Yola Reduziria o número de gravações se o singleton fosse programado para atualizar em um agendamento predeterminado e / ou fixo, reduzindo assim a contenção de threads. Ainda assim, você não seria capaz de testar com precisão qualquer código que interaja com o singleton a menos que simule uma instância que não seja de singleton que simule o mesmo uso. O pessoal do TDD provavelmente se encaixaria, mas funcionaria.
quer

@EvanPlaice: Mesmo com uma farsa, você teria alguns problemas com o código que diz Singleton.getInstance(). Um idioma que ofereça suporte à reflexão pode solucionar esse problema, definindo o campo em que a One True Instance está armazenada. Os testes da OMI, no entanto, tornam-se um pouco menos confiáveis ​​depois que você começa a brincar com o estado privado de outra classe.
cHao

28

Singleton não é uma instância única!

Ao contrário de outras respostas, não quero falar sobre o que há de errado com os Singletons, mas mostrar como eles são poderosos e impressionantes quando usados ​​da maneira certa!

  • Problema : O Singleton pode ser um desafio no ambiente com vários threads
    Solução : Use um processo de inicialização por thread único para inicializar todas as dependências do seu singleton.
  • Problema : É difícil zombar de singletons.
    Solução : Use o método Padrão de fábrica para zombar

Você pode mapear MyModelpara a TestMyModelclasse que a herda; em todos os lugares em MyModelque será injetado, você será TestMyModelinstruído. - Problema : singletons podem causar vazamento de memória, pois nunca foram descartados.
Solução : Bem, descarte-os! Implemente um retorno de chamada em seu aplicativo para descartar corretamente os singletons; remova todos os dados vinculados a eles e, finalmente: remova-os da fábrica.

Como afirmei no título singleton, não se trata de instância única.

  • Singletons aprimora a legibilidade : você pode olhar para sua classe e ver qual singleton injetou para descobrir quais são suas dependências.
  • Os singletons aprimoram a manutenção : depois de remover uma dependência de uma classe, você exclui alguma injeção de singleton, não precisa editar um grande link de outras classes que apenas mudaram sua dependência (esse é um código ruim para mim @ Jim Burger )
  • Os singletons aprimoram a memória e o desempenho : quando algo acontece em seu aplicativo e é necessária uma longa cadeia de retornos de chamada, você está desperdiçando memória e desempenho. Ao usar o Singleton, você está cortando o intermediário e aprimora o desempenho e o uso da memória ( evitando alocações desnecessárias de variáveis ​​locais).

2
Isso não trata do meu principal problema com os Singletons, que é o acesso ao estado global de qualquer uma das milhares de classes em seu projeto.
usar o seguinte comando

8
Isso seria o fim ...
Ilya gazman

LegendLength Por que isso está errado? Por exemplo, no meu aplicativo, tenho um Settingsobjeto singleton acessível a partir de qualquer widget, para que cada widget saiba como formatar os números exibidos. Se não fosse um objeto acessível globalmente, eu teria que injetá-lo no construtor para cada widget do construtor e manter a referência a ele como uma variável de membro. Isso é um terrível desperdício de memória e tempo.
VK

23

Minha resposta sobre como os Singletons são ruins é sempre "eles são difíceis de fazer o certo". Muitos dos componentes fundamentais das linguagens são singletons (classes, funções, namespaces e até operadores), assim como os componentes de outros aspectos da computação (host local, rota padrão, sistema de arquivos virtual etc.), e não é por acaso. Embora causem problemas e frustrações de tempos em tempos, também podem fazer muitas coisas funcionarem MUITO melhor.

Os dois maiores erros que vejo são: tratá-lo como um global e não definir o fechamento de Singleton.

Todo mundo fala sobre Singleton como globais, porque basicamente são. No entanto, grande parte (infelizmente, não todas) da maldade em um global não provém intrinsecamente de ser global, mas de como você a usa. O mesmo vale para Singletons. Na verdade, mais do que "instância única" realmente não precisa significar "acessível globalmente". É mais um subproduto natural e, dado o mal que sabemos disso, não devemos ter tanta pressa de explorar a acessibilidade global. Depois que os programadores veem um Singleton, eles parecem sempre acessá-lo diretamente por meio de seu método de instância. Em vez disso, você deve navegar para ele como faria com qualquer outro objeto. A maioria dos códigos nem deveria estar ciente de que está lidando com um Singleton (acoplamento flexível, certo?). Se apenas um pequeno pedaço de código acessar o objeto como se fosse global, muitos danos serão desfeitos.

O contexto Singleton também é realmente importante. A característica definidora de um Singleton é que existe "apenas um", mas a verdade é que é "apenas um" dentro de algum tipo de contexto / espaço de nome. Eles geralmente são um dos seguintes: um por encadeamento, processo, endereço IP ou cluster, mas também podem ser um por processador, máquina, espaço para nome do idioma / carregador de classes / qualquer que seja, sub-rede, Internet etc.

O outro erro, menos comum, é ignorar o estilo de vida de Singleton. Só porque existe apenas um, não significa que um Singleton seja onipotente "sempre foi e sempre será", nem é geralmente desejável (objetos sem início e fim violam todos os tipos de suposições úteis no código e devem ser empregados apenas nas mais desesperadas circunstâncias.

Se você evitar esses erros, os Singletons ainda podem ser uma PITA, mas estão prontos para ver que muitos dos piores problemas são significativamente mitigados. Imagine um Java Singleton, definido explicitamente como uma vez por carregador de classe (o que significa que precisa de uma política de segurança de encadeamento), com métodos definidos de criação e destruição e um ciclo de vida que determina quando e como eles são chamados e cujo método de "instância" foi proteção de pacote, para que geralmente seja acessada por outros objetos não globais. Ainda é uma fonte potencial de problemas, mas certamente muito menos problemas.

Infelizmente, ao invés de ensinar bons exemplos de como fazer Singletons. Ensinamos exemplos ruins, deixamos que os programadores fiquem usando-os por um tempo e depois dizemos que eles são um padrão de design ruim.


23

Consulte a Wikipedia Singleton_pattern

Também é considerado um antipadrão por algumas pessoas, que acham que é excessivamente usado, introduzindo limitações desnecessárias em situações em que uma única instância de uma classe não é realmente necessária. [1] [2] [3] [4]

Referências (apenas referências relevantes do artigo)

  1. ^ Alex Miller. Padrões que eu odeio # 1: Singleton , julho de 2007
  2. ^ Scott Densmore. Por que singletons são maus , maio de 2004
  3. ^ Steve Yegge. Singletons considerados estúpidos , setembro de 2004
  4. ^ JB Rainsberger, IBM. Use seus singletons com sabedoria , julho de 2001

8
Uma descrição sobre o padrão não explica por que ele é considerado como o mal ...
Jrgns

2
Dificilmente justo: "Também é considerado um antipadrão por algumas pessoas, que acham que é excessivamente usado, introduzindo limitações desnecessárias em situações em que uma única instância de uma classe não é realmente necessária". Olhe as referências ... De qualquer forma, existe RTFM para mim.
GUI toxicómano de

17

Não é que os singletons sejam ruins, mas o padrão de design do GoF é. O único argumento realmente válido é que o padrão de design do GoF não se presta em relação aos testes, especialmente se os testes forem executados em paralelo.

O uso de uma única instância de uma classe é uma construção válida, desde que você aplique os seguintes meios no código:

  1. Verifique se a classe que será usada como um singleton implementa uma interface. Isso permite que stubs ou zombarias sejam implementados usando a mesma interface

  2. Verifique se o Singleton é seguro para threads. Isso é um dado.

  3. O singleton deve ser simples por natureza e não excessivamente complicado.

  4. Durante o tempo de execução do aplicativo, em que os singletons precisam ser passados ​​para um determinado objeto, use uma fábrica de classes que construa esse objeto e faça com que a fábrica passe a instância singleton para a classe que precisa.

  5. Durante o teste e para garantir um comportamento determinístico, crie a classe singleton como uma instância separada como a própria classe ou um esboço / simulação que implemente seu comportamento e passe-o como está para a classe que o exige. Não use o fator de classe que cria o objeto em teste que precisa do singleton durante o teste, pois ele passará na única instância global dele, o que anula o objetivo.

Usamos Singletons em nossas soluções com bastante sucesso testável, garantindo um comportamento determinístico em fluxos de execução de testes paralelos.


+1, finalmente , uma resposta que aborda quando um singleton pode ser válido.
Pacerier

16

Eu gostaria de abordar os 4 pontos na resposta aceita, espero que alguém possa explicar por que estou errado.

  1. Por que ocultar dependências no seu código é ruim? Já existem dezenas de dependências ocultas (chamadas em tempo de execução C, chamadas à API do SO, chamadas de funções globais) e dependências singleton são fáceis de encontrar (procure por exemplo ()).

    "Tornar algo global para evitar distribuir é um cheiro de código". Por que não passar algo ao redor para evitar torná-lo um singleton com cheiro de código?

    Se você está passando um objeto por 10 funções em uma pilha de chamadas apenas para evitar um singleton, isso é ótimo?

  2. Princípio da responsabilidade única: acho que isso é um pouco vago e depende da sua definição de responsabilidade. Uma pergunta relevante seria: por que adicionar essa "responsabilidade" específica a uma questão de classe?

  3. Por que passar um objeto para uma classe o torna mais fortemente acoplado do que usá-lo como um singleton dentro da classe?

  4. Por que muda quanto tempo o estado dura? Singletons podem ser criados ou destruídos manualmente, para que o controle ainda esteja lá, e você pode tornar o tempo de vida igual ao tempo de vida de um objeto não-singleton.

Em relação aos testes de unidade:

  • nem todas as classes precisam ser testadas em unidade
  • nem todas as classes que precisam ser testadas em unidade precisam alterar a implementação do singleton
  • se eles fazem precisa ser unidade testada e fazer necessidade de alterar a implementação, é fácil mudar uma classe de usar um Singleton para ter o singleton passado para ele via injeção de dependência.

1
1. Todas essas dependências ocultas? Isso também é ruim. Dependências ocultas são sempre más. Mas, no caso do CRT e do SO, eles já estão lá e são a única maneira de fazer algo. (Tente escrever um programa C sem usar o tempo de execução ou o sistema operacional.) Essa capacidade de fazer coisas supera amplamente os negativos. Singletons em nosso código não recebem esse luxo; como estão firmemente dentro da nossa esfera de controle e responsabilidade, todo uso (leia-se: toda dependência oculta adicional) deve ser justificável como a única maneira razoável de fazer as coisas. Muito, muito poucos deles realmente são.
cHao 12/02

2. "Responsabilidade" é normalmente definido como "motivo para mudar". Um singleton acaba gerenciando sua vida útil e realizando seu trabalho real. Se você alterar a forma como o trabalho é feito ou como o gráfico de objetos é construído, é necessário alterar a classe. Mas se você tiver outro código para criar o gráfico de objetos e sua classe apenas fizer seu trabalho real, esse código de inicialização poderá configurar o gráfico de objetos da maneira que desejar. Tudo é muito mais modular e testável, porque você pode inserir dobras de teste e desmontar tudo à vontade, e não depende mais de partes móveis ocultas.
cHao 12/02

1
@cHao: 1. É bom que você reconheça que a "capacidade de fazer coisas supera amplamente os negativos". Um exemplo seria uma estrutura de log. É ruim exigir a passagem de um objeto de log global por injeção de dependência através de camadas de chamadas de função, se isso significa que os desenvolvedores são desencorajados a efetuar log. Portanto, singleton. 3. Seu ponto de acoplamento rígido é relevante apenas se você quiser que os clientes da classe controlem o comportamento via polimorfismo. Geralmente não é esse o caso.
13133 Jon

2
4. Não sei se "não pode ser destruído manualmente" é uma implicação lógica de "pode ​​ser apenas uma instância". Se é assim que você define singleton, não estamos falando da mesma coisa. Todas as classes não devem ser testadas em unidade. Essa é uma decisão comercial e, às vezes, o tempo de comercialização ou o custo de desenvolvimento prevalecem.
13133 Jon

1
3. Se você não deseja polimorfismo, nem precisa de uma instância. Você também pode transformá-lo em uma classe estática, pois está se vinculando a um único objeto e a uma única implementação - e pelo menos a API não está mentindo para você.
cHao

15

Vince Huston tem esses critérios, que me parecem razoáveis:

Singleton deve ser considerado apenas se todos os três dos seguintes critérios forem atendidos:

  • A propriedade da instância única não pode ser razoavelmente atribuída
  • Inicialização lenta é desejável
  • O acesso global não é fornecido de outra forma para

Se a propriedade da instância única, quando e como a inicialização ocorre, e o acesso global não são problemas, Singleton não é suficientemente interessante.


14

Singletons são ruins do ponto de vista purista.

Do ponto de vista prático, um singleton é um trade-off entre desenvolvimento e complexidade .

Se você sabe que seu aplicativo não vai mudar muito, eles são bastante aceitáveis. Saiba que você pode precisar refatorar as coisas se seus requisitos mudarem de maneira inesperada (o que é bastante bom na maioria dos casos).

Singletons às vezes também complicam o teste de unidade .


3
Minha experiência é que começar com singletons realmente o machucará mesmo no curto prazo, sem contar no longo prazo. Esse efeito pode ser menos se o aplicativo já existir há algum tempo e provavelmente já estiver infestado de outros singletons. Começando do zero? Evite-os a todo custo! Deseja uma única instância de um objeto? Deixe uma fábrica gerenciar a instanciação desse objeto.
Sven

1
O AFAIK Singleton é um método de fábrica. Portanto, não recebo sua recomendação.
Tacone 17/05

3
"A factory"! = "Um factory_method que não pode ser separado dos outros itens úteis da mesma classe"
Sven

13

Não há nada inerentemente errado com o padrão, supondo que ele esteja sendo usado para algum aspecto do seu modelo que seja verdadeiramente único.

Acredito que a reação se deve ao uso excessivo, que, por sua vez, se deve ao fato de ser o padrão mais fácil de entender e implementar.


6
Acho que a reação tem mais a ver com pessoas praticando testes de unidade formalizados, percebendo que são um pesadelo para lidar.
Jim Burger

1
Não sei por que isso está em -1. Não é a resposta mais descritiva, mas ele também não está errado.
Outlaw Programmer

13

Não vou comentar sobre o argumento do bem / do mal, mas não os uso desde a primavera . O uso da injeção de dependência removeu praticamente meus requisitos para singleton, servicelocators e fábricas. Acho esse ambiente muito mais produtivo e limpo, pelo menos para o tipo de trabalho que eu faço (aplicativos da Web baseados em Java).


3
não são Spring beans, por padrão, Singletons?
fino

3
Sim, mas quero dizer 'codificar' singletons. Eu não 'escrevi um singleton' (ou seja, com um construtor privado yada yada yada conforme o padrão de design) - mas sim, com a primavera estou usando uma única instância.
prule 16/02

4
então, quando outros o fazem, tudo bem (se eu usarei isso depois), mas se outros o fizerem e eu não o usaremos, é mau?
Dainius 24/10

11

Singleton é um padrão e pode ser usado ou abusado como qualquer outra ferramenta.

A parte ruim de um singleton geralmente é o usuário (ou devo dizer o uso inadequado de um singleton para coisas que ele não foi projetado para fazer). O maior infrator está usando um singleton como uma variável global falsa.


1
Obrigado Loki :) Exatamente o meu ponto. Toda a caça às bruxas me lembra o debate que vai. As ferramentas são para pessoas que sabem como usá-las; o uso de uma ferramenta que você não gosta pode ser perigoso para você, portanto evite-a, mas NÃO diga aos outros para não usarem / não aprenderem a usá-la corretamente. Não sou exatamente "pró-singleton", mas gosto do fato de ter uma ferramenta como essa e posso sentir onde é apropriado usá-la. Período.
dkellner

8

Quando você escreve código usando singletons, digamos, um logger ou uma conexão com o banco de dados, e depois descobre que precisa de mais de um log ou mais de um banco de dados, você está com problemas.

Singletons tornam muito difícil passar deles para objetos comuns.

Além disso, é muito fácil escrever um singleton não seguro para threads.

Em vez de usar singletons, você deve passar todos os objetos utilitários necessários de uma função para outra. Isso pode ser simplificado se você agrupar todos eles em um objeto auxiliar, como este:

void some_class::some_function(parameters, service_provider& srv)
{
    srv.get<error_logger>().log("Hi there!");
    this->another_function(some_other_parameters, srv);
}

4
Como o argumento de aprovação de cada método é brilhante, ele deve seguir pelo menos as 10 principais maneiras de poluir sua API.
Dainius 24/10

Essa é uma desvantagem óbvia, e que deveria ter sido tratada pela linguagem, por meio de argumentos que de alguma forma se propagam em chamadas aninhadas, mas na ausência desse suporte, isso deve ser feito manualmente. Considere que mesmo singletons naturais, como um objeto representando o relógio do sistema, têm potencial para problemas. Por exemplo, como você vai cobrir o código dependente do relógio (pense em vários medidores de eletricidade tarifária) com testes?
Roman Odaisky

Depende do que você está testando, se você não está testando Singleton, por que você se importa como ele se comporta, se o seu 2 objeto remoto depende de cada outro comportamento, não é singleton problema ..
Dainius

Você poderia fornecer qual idioma seria propagado em chamadas aninhadas?
Dainius

1
Se você tem um módulo que depende de outro e você não o conhece / não pode realizá-lo, você terá dificuldades, independentemente de ele ser único ou não. As pessoas estão usando o modo de herança com frequência para onde devem usar a composição, mas você não diz que a herança é ruim e o POO deve ser evitado a todo custo, porque muitas pessoas estão cometendo erros de design lá, ou você está?
Dainius

8

Os problemas com singletons são a questão do escopo aumentado e, portanto, do acoplamento . Não há como negar que existem algumas situações em que você precisa acessar uma única instância e isso pode ser realizado de outras maneiras.

Agora eu prefiro projetar em torno de um contêiner de inversão de controle (IoC) e permitir que a vida útil seja controlada pelo contêiner. Isso dá a você o benefício das classes que dependem da instância de não terem conhecimento do fato de que existe uma única instância. A vida útil do singleton pode ser alterada no futuro. Uma vez que esse exemplo que encontrei recentemente foi um ajuste fácil de thread único para multi-thread.

FWIW, se for um PIA quando você tentar fazer o teste de unidade, ele será PIA quando você tentar depurar, corrigir erros ou aprimorá-lo.



7

Singletons NÃO são ruins. Só é ruim quando você cria algo globalmente único que não é globalmente único.

No entanto, existem "serviços de escopo de aplicativos" (pense em um sistema de mensagens que faz com que os componentes interajam) - solicita uma classe de singleton, "MessageQueue" - que possui o método "SendMessage (...)".

Você pode fazer o seguinte em todo o lugar:

MessageQueue.Current.SendMessage (new MailArrivedMessage (...));

E, é claro, faça:

MessageQueue.Current.RegisterReceiver (this);

nas classes que implementam IMessageReceiver.


6
E se eu quiser criar uma segunda fila de mensagens, com um escopo menor, por que não devo reutilizar seu código para criá-lo? Um singleton impede isso. Mas se você tivesse acabado de criar uma classe de fila de mensagens comum e, em seguida, criar uma instância global para atuar como a de "escopo do aplicativo", eu poderia criar uma segunda instância para outro uso. Mas se você tornar a classe um singleton, eu teria que escrever uma segunda classe de fila de mensagens.
jalf

1
Além disso, por que não deveríamos apenas ter uma CustomerOrderList global para que possamos chamá-la perfeitamente de qualquer lugar como MessageQueue? Acredito que a resposta seja a mesma para ambos: está efetivamente criando uma variável global.
usar o seguinte comando

7

Muitas pessoas colocam objetos que não são seguros para threads em um padrão único. Eu já vi exemplos de um DataContext ( LINQ to SQL ) feito em um padrão singleton, apesar do DataContext não ser seguro para threads e é puramente um objeto de unidade de trabalho.


muitas pessoas escrevem código multithread inseguro, isso significa que devemos eliminar threads?
Dainius 24/10

@ Dainius: De fato, sim. Na IMO, o modelo de simultaneidade padrão deve ser multiprocesso, com uma maneira de dois processos (1) passarem mensagens entre si com facilidade e / ou (2) compartilharem a memória conforme necessário. A segmentação é útil se você deseja compartilhar tudo , mas nunca deseja isso de verdade. Pode ser emulado compartilhando todo o espaço de endereço, mas isso também seria considerado um antipadrão.
cHao

@ Dainius: E, claro, isso pressupõe que a simultaneidade honesta com a bondade seja necessária. Muitas vezes, tudo o que você quer é poder fazer uma coisa enquanto espera pelo sistema operacional fazer outra coisa. (Atualizando a interface do usuário durante a leitura de um soquete, por exemplo.) Uma API assíncrona decente pode tornar a segmentação completa desnecessária na grande maioria dos casos.
cHao

por isso, se você tem enorme matriz de dados, o que você precisa processar, é melhor fazer isso em único segmento, porque para muitas pessoas podem fazer isso errado ..
Dainius

@ Dainius: Em muitos casos, sim. (O encadeamento pode realmente atrasá-lo , se você adicionar sincronização à mistura. Este é um excelente exemplo de por que o multithreading não deve ser o primeiro pensamento da maioria das pessoas.) Em outros casos, seria melhor ter dois processos que compartilham apenas o material necessário. Obviamente, você precisaria organizar os processos para compartilhar memória. Mas, francamente, vejo isso como uma coisa boa - pelo menos muito melhor do que usar o modo de compartilhar tudo. Ele exige que você diga explicitamente (e, portanto, idealmente, saiba) quais partes são compartilhadas e, portanto, quais partes precisam ser seguras para threads.
cHao

6

Aqui está mais uma coisa sobre singletons que ninguém disse ainda.

Na maioria dos casos, "singletonidade" é um detalhe de implementação para alguma classe, e não uma característica de sua interface. Inversão do contêiner de controle pode ocultar essa característica dos usuários da classe; você só precisa marcar sua classe como um singleton (com@Singleton anotação em Java, por exemplo) e é isso; IoCC fará o resto. Você não precisa fornecer acesso global à sua instância de singleton porque o acesso já é gerenciado pelo IoCC. Portanto, não há nada errado com os singletons da IoC.

Os Singletons do GoF em oposição ao IoC Os Singletons devem expor "singletonidade" na interface através do método getInstance () e, portanto, sofrem com tudo o que foi dito acima.


3
Na minha opinião, "singletonidade" é um detalhe do ambiente de tempo de execução e não deve ser considerado pelo programador que escreveu o código da classe. Pelo contrário, é uma consideração a ser feita pelo USUÁRIO da classe. somente o USUÁRIO sabe quantas instâncias são realmente necessárias.
Earth Engine

5

Singletons não são maus, se você usá-lo corretamente e minimamente . Existem muitos outros bons padrões de design que substituem as necessidades do singleton em algum momento (e também oferecem melhores resultados). Mas alguns programadores desconhecem esses bons padrões e usam o singleton para todos os casos, o que torna o singleton ruim para eles.


Impressionante! Totalmente de acordo! Mas você poderia, e talvez devesse, elaborar muito mais. Como expandir quais padrões de design são geralmente ignorados e como "de maneira adequada e mínima" usar singletons. Mais fácil dizer do que fazer ! : P
cregox 16/11

Basicamente, a alternativa é passar objetos pelos parâmetros do método, em vez de acessá-los pelo estado global.
precisa saber é o seguinte

5

Em primeiro lugar, uma classe e seus colaboradores devem primeiro executar seu propósito pretendido, em vez de se concentrar nos dependentes. O gerenciamento do ciclo de vida (quando as instâncias são criadas e quando estão fora do escopo) não deve fazer parte da responsabilidade das classes. A melhor prática aceita para isso é criar ou configurar um novo componente para gerenciar dependências usando injeção de dependência.

Freqüentemente, o software fica mais complicado, faz sentido ter várias instâncias independentes da classe Singleton com diferentes estados. Confirmar código para simplesmente pegar o singleton está errado nesses casos. UsandoSingleton.getInstance() pode ser bom para pequenos sistemas simples, mas não funciona / dimensiona quando é necessário uma instância diferente da mesma classe.

Nenhuma classe deve ser considerada um singleton, mas sim uma aplicação de seu uso ou de como é usada para configurar dependentes. Para um processo rápido e desagradável, isso não importa - basta codificar como o caminho dos arquivos não importa, mas para aplicativos maiores essas dependências precisam ser fatoradas e gerenciadas de maneira mais apropriada usando o DI.

Os problemas que os singleton causam nos testes são um sintoma de seu caso / ambiente de uso único codificado. O conjunto de testes e os vários testes são individuais e separam algo que não é compatível com a codificação embutida de um singleton.


4

Como são basicamente variáveis ​​globais orientadas a objetos, você geralmente pode projetar suas classes de forma a não precisar delas.


Se a sua classe não se limitar a uma única instância, você precisará de membros estáticos na sua classe gerenciados por semáforos, o que resulta praticamente na mesma coisa! Qual é a sua alternativa proposta?
Jeach

Eu tenho um aplicativo enorme com um "MainScreen". Essa tela abre muitas janelas modais / não modais menores / formulários de interface do usuário. IMHO Eu sinto que o MainScreen deve ser um singleton, de modo que, por exemplo, um widget em algum canto do aplicativo queira mostrar seu status na barra de status do MainScreen, tudo o que ele precisa fazer é MainScreen.getInstance (). SetStatus ( "Algum texto"); O que você propõe como alternativa? Passe MainScreen em todo o aplicativo? : D
Salvin Francis

2
@SalvinFrancis: O que eu recomendaria é que você pare de ter objetos que se importam com coisas com as quais eles não deveriam se importar e esgueire-se pelo aplicativo para brincar um com o outro. :) Seu exemplo seria muito melhor feito com eventos. Quando você realiza os eventos corretamente, um widget nem precisa se preocupar se há um MainScreen; apenas transmite "ei, as coisas aconteceram" e o que quer que tenha se inscrito no evento "as coisas aconteceram" (seja um MainScreen, um WidgetTest ou algo completamente diferente!) decide como deseja responder. É assim que o POO deve ser feito de qualquer maneira. :)
Chao

1
@ Salvin Considere como é difícil argumentar sobre o MainScreen ao depurar se ele está sendo 'silenciosamente' atualizado por muitos componentes. Seu exemplo é um motivo perfeito para singletons serem ruins.
precisa saber é o seguinte
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.