sorry taborda, editei apagando o que vc quotou antes de ver sua resposta
Mas é justo esse o ponto! Esses patterns hoje estão dentro dos containers IoC, a gente não escreve mais essas coisas.
Aliás, ninguém chama o getBean no Spring diretamente, certo? Senão ele seria um Registrizão esperto, apenas isso (como voce mesmo disse).
Creio que todos estamos falando o mesmo: o pessoal costuma usar singleton erroneamente, por isso precisam ter cuidado, como o proprio Erich Gamma disse: I’m in favor of dropping Singleton. Its use is almost always a design smell. Da até pra ver isso nessa sua frase:
Exatamente, mas é detalhe de nomeclatura para facilitar, todos estão falando a mesma coisa aqui. A maioria do pessoal queria um shared object, e não um singleton! (e muitas vezes é até questionável a necessidade de shared object).
Em nenhum momento dissemos que singleton esta sempre errado, ou que não se deve estudar Design Patterns, etc. Como você disse, devemos aprender a usa-los, mas direito.
[quote=Alessandro Lazarotti][editado por mim mesmo - estava redundante com o que o Sergio escreveu ]
… menos a parte de @Singleton. Qual mal vc vê nesta anotação Sergio Lopes? E você Taborda, que mal você vê em uma anotação que realmente provê a criação única de um objeto em memória? Somente o nome? Se for isso o que vc sugeriria, apenas por curiosidade.
[/quote]
-
Essa anotaçao não proves a criação unica na memoria. Se eu quiser criar outro eu posso. É só dar new. Um verdadeiro singleton vc não tem sequer como controlar a criação. Vc não pode criar outro mesmo que queira.
Um objeto que é instanciado uma vez por escolha ( para poupar memoria por exemplo) é um Shared Object, não um Singleton. são padrões diferentes que servem para coisas diferentes. Exemplo , Integer tem charedobjects para numeros no range de byte, Locale e Currency e outros usam isso tb. É um padrão bem comum para minimizar a criação redundante de objetos. -
dado o argumento anterior o nome é horrivel. Deveria ser @Shared. ou @Unique ou qq outro abdejetivo. Tods menos Singleton.
[quote=sergiotaborda]Veja bem o conceito de singleton nasce da proibição explicita de injeção de dependencia que é um principio da OO. Portanto, não faz sentido que um motor de injeção possa criar um singleton. É como ter uma fabrica de singleton, simplesmente impossivel.
O ponto que abordei é a confusão de que um singleton possa ser criado via motor de DI. Não pode. [/quote]
Agora entendi o seu ponto. Então discordamos mesmo (nestes pontos, pelo menos).
Eu consigo enxergar um singleton sendo criado fora da classe, desde que esse ser externo garanta a instância única. Claro, é uma visão diferente do GoF tradicional, e mais próxima do que se enxerga como singleton hoje no Spring e no próprio @Singleton
[quote=Paulo Silveira]
Creio que todos estamos falando o mesmo: o pessoal costuma usar singleton erroneamente, por isso precisam ter cuidado, como o proprio Erich Gamma disse: I’m in favor of dropping Singleton. Its use is almost always a design smell. [/quote]
Não creio que estamos. A frase que cistaste é um exemplo. O que é um smell ? o singleton ?
coitado. porque ele é , e registry ou factory ou proxy não são ? Porque se livrar ( drop) do singleton. Tipo todos os autores vão nunca mais escrever sobre ele, logo ele nunca mais será usado. Entendem ? isso não faz sentido.
O que ele deveria dizer era : precisamos explicar melhor, com mais exemplos para que as pessoas não achem que estão usando o padrão.
Um padrão tem um escopo onde pode ser usado. A maioria usa singleton no escopo errado. A implementação tecnica pode até ser perfeita, mas se o escopo é errado, é um smell. O escopo do uso, não o padrão e não o coitado do singleton.
Para os que não sabem porque eu estou falando o que estou falando releiam o topico todo ( e os n-trocentos do mesmo assunto).
[quote=Sergio Lopes][quote=sergiotaborda]Veja bem o conceito de singleton nasce da proibição explicita de injeção de dependencia que é um principio da OO. Portanto, não faz sentido que um motor de injeção possa criar um singleton. É como ter uma fabrica de singleton, simplesmente impossivel.
O ponto que abordei é a confusão de que um singleton possa ser criado via motor de DI. Não pode. [/quote]
Agora entendi o seu ponto. Então discordamos mesmo (nestes pontos, pelo menos).
Eu consigo enxergar um singleton sendo criado fora da classe, desde que esse ser externo garanta a instância única. Claro, é uma visão diferente do GoF tradicional, e mais próxima do que se enxerga como singleton hoje no Spring e no próprio @Singleton[/quote]
Dê um exemplo. Crie um mecanismo para criar o objeto de forma que ele seja um singleton sem que a classe crie o objeto. ( teste com runtime e desktop para ver se funciona. lembre-se que runtime é um recurso realmente único. )
Tem razao. Tirar do livro é exagero. Melhor seria ter esse tipo de discussão lá e mostrar exatamente o smell, mostrando que não é legal usar como variável global, difícil de testar se invocado o método estático em todos os lugares, etc, mas que da pra usar bem se tomar cuidado E tiver a real necessidade (que é dificil aparecer).
[quote=sergiotaborda]
Dê um exemplo. Crie um mecanismo para criar o objeto de forma que ele seja um singleton sem que a classe crie o objeto. ( teste com runtime e desktop para ver se funciona. lembre-se que runtime é um recurso realmente único. )[/quote]
Crie uma interface publica que se chama Runtime e uma implementacao package-protected que se chama DefaultRuntime. Registre essa configuracao no seu container de DI, de que deve ter so um DefaultRuntime a ser injetado. O container usando um pouco de magica consegue dar new na classe paclage-protected. Pronto! Podia ate ter na System um getRuntime que devolvesse o DefaultRuntime unicamente instanciado. Codigo limpo, testavel (diferente de como é atualmente, impossivel de se testar unitariamente quem depende diretamente de Runtime sem magia negra), e é uma forma de implementar singleton. A unica forma de burlar isso seria por reflection+magia, e da pra fazer a mesma coisa com o singleton tradicional, entao estamos igualmente protegidos. Alias, essa tecnica é pra la de conhecida e muita gente usa de outras formas.
A falta de uma interface para Runtime, e qualquer outro singleton, é certamente um pequeno pecado.
Essa visao do Sergio Lopes, como ele disse, é diferente da tradicional, mas tem o mesmo efeito.
[quote=sergiotaborda][quote=Paulo Silveira]
Creio que todos estamos falando o mesmo: o pessoal costuma usar singleton erroneamente, por isso precisam ter cuidado, como o proprio Erich Gamma disse: I’m in favor of dropping Singleton. Its use is almost always a design smell. [/quote]
Não creio que estamos. A frase que cistaste é um exemplo. O que é um smell ? o singleton ?
coitado. porque ele é , e registry ou factory ou proxy não são ? Porque se livrar ( drop) do singleton. Tipo todos os autores vão nunca mais escrever sobre ele, logo ele nunca mais será usado. Entendem ? isso não faz sentido.
O que ele deveria dizer era : precisamos explicar melhor, com mais exemplos para que as pessoas não achem que estão usando o padrão.
Um padrão tem um escopo onde pode ser usado. A maioria usa singleton no escopo errado. A implementação tecnica pode até ser perfeita, mas se o escopo é errado, é um smell. O escopo do uso, não o padrão e não o coitado do singleton.
Para os que não sabem porque eu estou falando o que estou falando releiam o topico todo ( e os n-trocentos do mesmo assunto).
[/quote]
Sinceramente nao foi o que entendi da frase do Gamma, ele disse que o USO do singleton é na maior parte um smell e nao propriamente o singleton.
[quote=fredferrao][quote=sergiotaborda]O que é um smell ? o singleton ?
coitado. porque ele é , e registry ou factory ou proxy não são ?
[/quote]
Sinceramente nao foi o que entendi da frase do Gamma, ele disse que o USO do singleton é na maior parte um smell e nao propriamente o singleton.[/quote]
verdade, bom ponto. ja estava respondido.
Taborda, acredito mais na resolução das motivações descritas nos catalogos do que nos padrões conforme criados em sua essência. Ainda insisto na implicancia com anotações como @Singleton. De fato é uma factory que o cria, mas se o container que a contém é responsável pela ciclo de vida do objeto e garante que ele é único, mesmo isso não estando no objeto, ele resolve a questão Singleton de “possuir apenas uma instancia na aplicação”. A associação deste comportamento com o nome “Singleton” é muito forte, logo não vejo mal em criar uma anotação com o mesmo nome para propósito similar.
O mesmo vale para mecanismos de cluster de alguns appservers onde para garantir um “comportamento Singleton” em mais de uma maquina virtual , é habilitado um servico ativo/passivo onde o controle da instancia fica a cargo do container e não do objeto… tendo o exato comportamento Singleton do padrão (vide HA-Singleton).
Sim, tão genial que não preciso me preocupar com isso e mais, se me preocupar, é com apenas 1.
Irinia ou não, simplicidade é genialidade e complexidade não é talento. Quero me preocupar com o negócio que o cliente deseja fazer funcionar e que me dê suporte para testar e retestar se eu alterar. Pouco importa qual pattern usou o sistema para o cliente e sinceramente, o que mais me importa é criar um software funcional, no prazo e ao mesmo tempo não seja um emaranhado de classes com nomenclaturas e padrões que mudam todas as horas.
Novamente, 1 padrão. Não mais que isso. De quantos padrões se faz um aplicativo em java? Será que levaria quanto tempo para entender tal padrão? Será que preciso saber ele para escrever bom software no Rails? A resposta é NÃO!
Agora, um framework X + Y + Z ainda preciso saber pattern A+B+C, logo, aqui estou, NA MESMA. Ai vem outro e quer adicionar mais um padrão XYZ porque é melhor que usar ABC e pronto, LÁ VAMOS NóS no barco da complexidade.
Enquanto isso, em uma linguagem bem elaborada necessita de 1 pattern, não me faça rir.
Só ler livros não lhe faz um bom programador. Só praticar também não. Precisamos dos dois e ao mesmo tempo, o $$$ é necessário para conseguirmos mais livros.
Não culpo a Sun e nem o Java. Pra ser sincero, nem sei porque tamanha complexidade é dão idolatrada e dão adotada nas empresas e porque, uma linguagem tão mais inteligente, mais fácil de escrever não teve seu lugar ao sol como o Java. Seria porque a Sun já foi bem grande? Talvez, olha o .Net, Microsoft por trás e pum, as empresas grandes adotam.
[quote=Sergio Lopes]
…
Compare qual código deixa as duas classes mais desacopladas:
class PrecisoDeUmCaraSingleton {
PrecisoDeUmCaraSingleton() {
SouUmSingleton s = SouUmSingleton.getInstance();
}
}
ou:
class PrecisoDeUmCaraQueNãoSeiSeÉSingleton {
PrecisoDeUmCaraQueNãoSeiSeÉSingleton(NãoSeiSeÉSingletonENãoMeInteressa n) {
// injecao de dependencia
}
}
No fim, singleton hoje deixou de ser Design Pattern de código e passou a ser configuração de escopo em containers IoC.[/quote]
Oi Sergio,
não estou aqui dizendo se Singleton é bom ou ruim, mas, na minha opinião, seu código mostra um problema de dependência, e não de singleton. Por exemplo:
class PrecisoDeUmCaraQueNãoSeiSeÉSingleton {
PrecisoDeUmCaraQueNãoÉSingleton() {
NaoÉSingleton n = new NãoÉSingleton();
}
}
acima temos um acoplamento maior independente do singleton em si.
class PrecisoDeUmCaraQueNãoSeiSeÉSingleton {
PrecisoDeUmCaraQueNãoÉSingleton(NãoÉSingleton n) {
// injecao de dependencia
}
}
Ola Salgado!
Voce tem razao, e o Sergio Lopes quis apontar realmente o problema da dependencia: usar o singleton sem cuidado gera um acoplamento fortissimo, dificultando tudo inclusive testes unitarios. Assim como o Erich Gamma tambem disse, o problema é nao usar o padrao direito, e nao o padrão em si.
[quote=Paulo Silveira]Ola Salgado!
Voce tem razao, e o Sergio Lopes quis apontar realmente o problema da dependencia: usar o singleton sem cuidado gera um acoplamento fortissimo, dificultando tudo inclusive testes unitarios. Assim como o Erich Gamma tambem disse, o problema é nao usar o padrao direito, e nao o padrão em si.[/quote]
Paulo,
levando em conta as duas implementacoes ‘erradas’ abaixo:
[code]class PrecisoDeUmCaraSingleton {
PrecisoDeUmCaraSingleton() {
SouUmSingleton s = SouUmSingleton.getInstance();
}
}
class PrecisoDeUmCaraQueNãoSeiSeÉSingleton {
PrecisoDeUmCaraQueNãoÉSingleton() {
NaoÉSingleton n = new NãoÉSingleton();
}
}
[/code]
o teste das 2 implementações fica difícil independente do singleton (como dito antes).
Quando não é singleton nada pode ser feito, quando é singleton, alguns gatos são possíveis:
[code]public void testGatoParaTestarAlgumaCoisa {
SouUmSingleton aInstanciaParaTeste = SouUmSingleton.getInstance();
/*
Via reflection o estado interno do singleton.
*/
// Chama método de PrecisoDeUmCaraSingleton. Que vai utilizar o singleton modificado.
}[/code]
Código mau feito é difícil de testar. Mas nesse caso específico, com singleton ainda é possível tentar fazer um gato.
Acredito que este artigo da InfoQ vem bem a calhar nesta discussão:
Como o Luca disse, sobre se preocupar com o problema primeiro e refatorar depois, tenho a dizer que isso só é válido se vc sabe dos juros que serão cobrados sobre isso.
A refatoração deve acontecer a todo momento [Martin Fowler], vc se preocupa inicialmente somente com o problema e aí vai refatorando, refatorando até ter um código “decente”.
A aplicação de Patterns, além de mostrar soluções para problemas conhecidos, também favorece uma comunicação universal entre os desenvolvedores.
Como foi dito aqui, só use Patterns se vc realmente tem um problema que precise dele. Mta gente utiliza Patterns apenas por usar e sem saber o pq ele realmente existe.
Mas se tratando do problema da curva de conhecimento necessária, creio que É necessária. Se podemos evitar defeitos futuros, pq não saber como evitar?
Palavras de Mary Poppendieck:
“O maior defeito que temos agora [em desenvolvimento de software] é tolerar defeitos”
Abraços.
Pois é, foi isso que ele disse. E é exactamente esse o problema. Quando vc usa o singleton corretamente isso não é errado. Exemplos sao Runtime e Desktop do JSE. quando cria um objeto que não é um singleton ,mas vc implementa o codigo igual ao que usaria num singleton isso sim é errado. Mas veja, não é o padrão que está errado, é o entendimento do programador que achou que singleton serve para dar acesso global.
Ainda hoje estava repassando um artigo da javamagazine sobre jruby e o autor escrevia algo como (parafrase) :" podemos tornar o objeto jrubyqualquercoisa (não lembro de cabeça o nome e não tenho a revista aqui) um singleton para podermos ter acesso global"
Este é o exemplo típico do mau uso de singleton. Quer acesso global ? use Registry. Quer uma única instância ? use singleton.
Singleton não é para dar acesso global (senão o nome do padrão seria Globalizator )
Um comentário geral.
O exemplo do Paulo de como implementar singleton não é válido. Acho que vcs sempre se esquecem do essencial e continuam confundindo singleton e shared. Veja bem, o propósito do singleton não é manter um objeto unico na memória. Isso o shared tb faz. O objetivo é proibir que mais do que um objeto seja criado sob qualquer condição. Se vc usa interfaces as possibilidades do numero de objetos é ilimitada. A unica forma de proibir a instanciação é ter uma classe final e com construtor privado. Se o construtor é privado apenas a classe ela mesma ,pode criar a unica instância que existirá. Leiam o Effective Java para mais detalhes.
Os motores de injeção são feitos de vários padrões. claro. A questão é que em algum ponto os objetos que eles injetam têm que ser criados. Durante a fase de criação ela só pode ser feita por um padrão criacional.
A diferença entre um shared e um singleton é que o shared usa uma única instancia por escolha. Ele escolhe pegar um objeto qualquer e só instanciá-lo uma vez. Não importa se o objeto pode ser instanciado mais vezes, ele só o faz uma vez.
O singleton só cria uma unica instancia porque só uma é possivel. Mesmo que eu queira criar outra eu não vou conseguir. Não importa quem está usando o objecto , nem porque, o mecanismo de criação estão armadilhado para que apenas uma instancia seja possivel de ser criada.
Um objeto shared pode ser descartado, e um outro da mesma classe colocado no seu lugar. Um objeto singleton não pode ser descartado. Por tudo que vc faça sempre apenas será possivel criar apenas uma instancia.
Como já disse, não é possivel usar um motor de injeção para criar um singleton, porque o singleton é feito proibindo toda e qualquer inversão de controle relativa à criação do objeto da classe. O mecanismo de controle da criação tem que ser tal que em qualquer uso da classe apenas uma instância seja criada. Então, tem que funcionar assim, mesmo na ausência de um motor de DI.
Lembrem-se que o singleton é um padrão criacional.
@Singleton é uma aberração por estes motivos. Vc cria um session bean. Vc cria uma interface e uma implementação. A implementação não tem qualquer mecanismo que evite que mais do que um objeto seja criado. aliás, a especificação manda que tenha um construtor publico sem argumentos. Um construtor publico é a antitese do singleton.
O que @Singleton significa é : crie uma instancia desta classe e mantenha-a criada. Sempre que alguem pedir por uma instancia desta classe retorne esta que vc mantem. É uma forma de cache que só permite guardar um objeto de cada classe. (Isto é o padrão Shared Object). O @Singleton não evitará que mais um objeto seja criado. É simples pq. Se o contrutor é publico e sem argumentos nada me impede de requisitar um novo objeto dando um new.
Mais uma vez : singleton não significa “mantenha uma unica instancia” significa “não permita que mais do que uma seja criada”. Este não permita é uma condição forte. Não permita sob nenhuma condição. E é por isso que ele é um padrão criacional.
Algumas pessoas falam que reflection estraga o padrão singleton. Tente usar reflection para criar uma instancia de Runtime ou Desktop.
Algumas pessoa falam que serializable estraga o padrão singleton. Ora, se um objeto é serializavel e pode ser enviado a outra máquina ou para o disco, é obvio que este objeto está sendo partilhado por estes diversos lugares. Ele é , na realidade um shared object.Chamar-lhe singleton nao o torna singleton. Experimente usar esses truques para instanciar Runtime ou desktop.
Singletons verdadeiros são invioláveis. Caso contrário não são singletons, mesmo que sejam chamados de singletons em alguma documentação.
A taxionomia dos padrões é bem clara e acontece ao nivel abstrato e das responsabilidades , nunca da implementação. Julgar se o objeto X é singleton ou não depende de várias coisas. Se alguma delas falha, o objeto não é um singleton.
Mecanismos de DI não podem tornar uma classe singleton. Não é possivel. Simplesmente não é. Eles tornam shared facilmente,mas não singleton.
O adjetivo Singleton usado em @Singleton e na documentação de motores de DI é um erro historico. É uma má interpretação do padrão singleton (na realidade é um truque de publicidade para fazer o motor melhor do que é prometendo que ele gerencia singletons. O que é mentira) . mas o fato de ser usado assim, chamado assim , não significa que o padrão singleton está sendo usado. Não está. O @Singleton é a perpetuação do smell de mal-usar o padrão singleton. Ele é tão aberrante quanto usar singleton para fazer o acesso global.
Em que condições os singletons são interessantes?
Imagino que em ambientes com restrições de memória e uma unica instância de jvm eu posso querer usar singletons, mas por economia. Ou não?