Padrão Singleton quando usar? Ou Simplesmente não Usar?

Bom primeiramente creio que discussões sobre padrões são pertinentes a esse fórum, creio que estou no lugar certo.
Mas se não estiver me falem.

Bom li aqui no fórum mesmo e no google sobre Singleton e me surgiram algumas dúvidas.

A princípio me pareceu uma idéia legal.
(Singleton é utilizado quando vc precisa de apenas um instancia de um determinado objeto na aplicação e quando este objeto tem um alto custo).

Alguns exemplos que observei na internet : Classe de Log, conexao e Classes de configuração(Classe que concentram configurações).

Estava quase convencido que era algo legal.

Mas daí resolvi ler no guj.

Vi altas críticas a esse padrão , tornar as classes burras e até mesmo que static e final deveriam ser apenas utilizado
em primitivos e de preferência com final.

Outra solução que propuseram foi trocar singleton por injeção(Injetar não costuma ser sempre um objeto novo).

Ainda surgiu uma dúvida referente a factory de conexão de banco.

Se usar um sigleton para isso todas as minhas classe terão a mesma conexao.

No caso de threads todas elas teriam o mesmo objeto.

Isso ocasionaria erro de concorrência certo?

Em uma aplicação que tenho aqui o que faço é usar uma factory com metodo getConnection();

Essa factory é chamada toda vez que passo pelo filtro.(No meu caso qualquer requisição )

Nesse caso antes da aplicação rodar eu chamo a factory e capturo uma conexao, essa conexao eu penduro na sessão e meu processamento continua normalmente chegando ao FrontController()

O FrontController por sua vez recebe a requisição e determina qual a lógica a ser processada

Ao termino da aplicação eu fecho a conexão.

Nesse caso eu teria uma conexão por request.(toda requisição passa pelo front controller), certo?

Mas se eu quisesse ter uma requisição por thread?

E se eu quisesse que uma conexão fosse compartilhada por várias threads.(e enfileiradas para serem atendidas).

Se eu quisesse ter um número de conexões ou uma regra que permita que a cada 100 usuários fosse criado uma nova conexão?

[quote=Rocklee6544]Bom primeiramente creio que discussões sobre padrões são pertinentes a esse fórum, creio que estou no lugar certo.
Mas se não estiver me falem.

Bom li aqui no fórum mesmo e no google sobre Singleton e me surgiram algumas dúvidas.

A princípio me pareceu uma idéia legal.
(Singleton é utilizado quando vc precisa de apenas um instancia de um determinado objeto na aplicação e quando este objeto tem um alto custo).

Alguns exemplos que observei na internet : Classe de Log e factory.

Estava quase convencido que era algo legal.

Mas daí resolvi ler no guj.

Vi altas críticas a esse padrão , tornar as classe burras e até mesmo que static e final deveria ser apenas utilizado
em primitivos e de preferência com final.

Outra solução que propuseram foi trocar singleton por injeção (mas injetar ,não é sempre um objeto novo).

[/quote]

bom… a minha opinião é que singleton tem uma coisa em comum com todos os outros padrões de projetos, ele é bom para ser usado em um cenário especifico… simples assim. As vezes você não pode ter dois objetos daquele determinado tipo, se for aplicado neste contexto então ele funciona bem… os motivos para você precisar de apenas um deste objeto variam, podem ser vários, mas em certos casos, você ter mais de um deste objeto atrapalha…

Creio que para factory o sigleton é legal.

Pois não a necessidade de se ter mais de uma fábrica do mesmo objeto.

Quanto ao log também me parece um caso interessantes.

Mas quanto a conexão, usar ou não usar singleton?

Eu fico tranquilo quando penso em algo que vai ser acessado por uma única pessoa, mas como esse cenário não ocorre
a minha maior preocupação é como o Singleton lida com threads(concorrência).

Sei que mesmo em threads o padrão singleton é compartilhado.(Isso não causa sobrecarga e mais que sobrecarga inconsistência
caso eu tenha dois processos escritores?).

Muito obrigado pela resposta.(Darei uma olhada em threads pelo que vi o modificador synchronized faz com que um recurso seja acessado no processo escritor por vez, ele meio que deixa enfileirado, certo?).

[quote=Rocklee6544]Creio que para factory o sigleton é legal.

Pois não a necessidade de se ter mais de uma fábrica do mesmo objeto.

Quanto ao log também me parece um caso interessantes.

Mas quanto a conexão, usar ou não usar singleton?

Eu fico tranquilo quando penso em algo que vai ser acessado por uma única pessoa, mas como esse cenário não ocorre
a minha maior preocupação é como o Singleton lida com threads(concorrência).

Sei que mesmo em threads o padrão singleton é compartilhado.(Isso não causa sobrecarga?).

Muito obrigado pela resposta.[/quote]

Encapsular uma conexão ao banco em um Singleton é um tiro de bazuca no pé! Servidores Web tratam requisções em threads separada justamente para aproveitar o número de processadores das máquinas e diminuir o tempo de resposta das requisições. Daí você tem uma série de requisições sendo tratadas em paralelo e você resolve enfileirar todo mundo na mesma conexão com o banco de dados ?

Por outro lado, abrir conexões para todas as requisições pode derrubar seu banco de dados, e pode haver problemas de concorrência também no banco. Assim, o ideal para tratar conexões é usar um pool gerenciando o número mínimo e máximo de conexões, etc.

Enfim, é preciso pensar muito bem antes de aplicar o Singleton, ver se realmente necessário. Usar por simples vontade de usar traz muito mais problemas do que solução.

rmendes08

Pelo que vc falou posso dizer que um usuário pode ter varias threads recebendo suas requisições , depois repassando para uma
mesma Servlet e que essa servlet pode ter também várias threads de diferente usuários.

Ou seja tenho uma única servlet tratando sei lá 100 usuários (pelo que o meu professor disse) e por dedução minha (Eu teria uma thread para cada usuário).

Essas threads não são enfileiradas para ter um tempo de resposta menor como vc disso e são atendidas pela mesma servlet.
Não poderia ocorrer problema de concorrência e sobrecarga(devido a várias threads acessarem um mesmo servlet(FrontController) para o mesmo recurso)?(Como isso funciona?)

O singleton não é uma boa para conexões. De maneira geral, é uma má prática deixar conexões para sempre abertas, como muita gente faz. Você consome um recurso precioso de banco de dados, mesmo que um determinado usuário não esteja usando a conexão.

O ideal mesmo é você deixar o seu ConnectionManager singleton. Ele produz novas conexões. Aí você pode colocar nele políticas de cache e um serviço avançado para tratar conexões do jeito certo (ou usar uma implementação já pronta, como o Jakarta DBCP ou o C3P0).

No caso de games, é muito comum usar Singleton para a tela do jogo (muitos jogos só suportam uma única), para o gerente de entidades ou para o SceneGraph.

Eu particularmente evito singletons ao máximo. Mas não vejo padrão melhor para quando você precisa relamente de um único objeto.
Ainda assim, cuidado com implementações de Singleton com lazy creation. Julgue se isso é realmente necessário, pois é esse tipo de construção que gera boa parte dos problemas que muita gente fala a respeito do singleton.

Fábricas de objeto são bons singleton se não possuírem estado (stateless) ou se o estado nunca é controlado diretamente pelo programador (como uma fábrica com DI).
Nos outros casos, talvez vc queira ter fábricas diferentes para situações diferentes, aí não seria o caso de usar Singleton.

[quote=Rocklee6544]rmendes08

Pelo que vc falou posso dizer que um usuário pode ter varias threads recebendo suas requisições , depois repassando para uma
mesma Servlet e que essa servlet pode ter também várias threads de diferente usuários.

Ou seja tenho uma única servlet tratando sei lá 100 usuários (pelo que o meu professor disse) e por dedução minha (Eu teria uma thread para cada usuário).

Essas threads não são enfileiradas para ter um tempo de resposta menor como vc disso e são atendidas pela mesma servlet.
Não poderia ocorrer problema de concorrência e sobrecarga(devido a várias threads acessarem um mesmo servlet(FrontController) para o mesmo recurso)?(Como isso funciona?)[/quote]

Como já havia dito, o servidor Web aloca 1 thread para cada requisição de usuário. Assim como conexões, os servidores mais robustos utilizam pool de threads ao invés de criar e destruir threads a todo momento. Inclusive, o tamanho do pool é configurável (provavelmente um pool de 100 threads é pouco para um ambiente de produção).

Como cada requisição é tratada por uma única trhread, logo cada chamada a doGet/doPost é tratada em uma thread separada. E sim, é possível ter várias trheads executando chamadas de um mesmo usuário.

Agora, o que confunde muito quem está começando é o fato de que, apesar de cada requisição ser tratada por uma thread separada, nem sempre é criada uma nova instância do Servlet. Você pode inclusive ter 1 única instância de um Servlet atendendo a uma centena de requisições. É por esse motivo que você não pode usar variáveis de instância em Servlets, pois pode gerar diversas inconsistências. Inclusive, se você precisar acessar uma HttpSession, esse acessado precisa ser feito dentro de um bloco sincronizado.

tiro de bazuca no pé… realmente achei essa colocação bem adequada…rs

Minhas experiências com singleton não foram boas no que diz respeito a conexões com banco, problemas de concorrência dentro do próprio JDBC, e problemas realmente “escrotos” de identificar, podem vir de um singleton. Mas também temos singletons para dispositivos de hardware que caíram como um luva, e já estão a mais de 5 ou 6 anos em produção sem problemas.

Como já foi dito, se sua aplicação usa conexões de forma intensa, use um pool, se não, crie conexões normalmente (também não adianta usar “complexidade gratuita” na sua aplicação).