Sobre Singleton

37 respostas
J

Já sei que alguns vão falar que não é uma boa idéia, mas eu preciso dessas informações durante toda a *vida* da aplicação.

Então, o que está errado nesse Singleton (bean)?

public class UsuarioFormBeanSingleton {
    
    private Integer codigo;
    private String nome;
    private String senha;
    private Integer nivel; // nivel de acesso de cada usuario
    
    /** Creates a new instance of UsuarioFormBeanSingleton */
    private UsuarioFormBeanSingleton() {}
    private static UsuarioFormBeanSingleton instancia = new UsuarioFormBeanSingleton();
    
    public static synchronized UsuarioFormBeanSingleton getInstacia(){
        return getInstancia();
    }

    public Integer getCodigo() {
        return codigo;
    }

    public void setCodigo(Integer codigo) {
        this.codigo = codigo;
    }

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public String getSenha() {
        return senha;
    }

    public void setSenha(String senha) {
        this.senha = senha;
    }

    public Integer getNivel() {
        return nivel;
    }

    public void setNivel(Integer nivel) {
        this.nivel = nivel;
    }

    public static UsuarioFormBeanSingleton getInstancia() {
        return instancia;
    }

    public static void setInstancia(UsuarioFormBeanSingleton aInstancia) {
        instancia = aInstancia;
    }    
}
Aí, exemplo, no início da aplicação eu faço isso:
UsuarioFormBeanSingleton usuarioSingleton = UsuarioFormBeanSingleton.getInstacia();
usuarioSingleton.setNome("Francisco");
usuarioSingleton.setCodigo(2008);
Aí vou em outra parte da aplicação e tento pegar o valor da propriedade porém imprime null:
UsuarioFormBeanSingleton usuarioSingleton = UsuarioFormBeanSingleton.getInstacia();
System.out.println("Nome usuario: "+usuarioSingleton.getNome()); // imprime null

Por que ele não mantém o valor que eu informe para a propriedade?

37 Respostas

V

deixa eu ver se eu entendi:

public static synchronized UsuarioFormBeanSingleton getInstacia(){  
         return getInstancia();  
     }

getInstacia() retorna ele mesmo? recursividade?

R

Correções:

private static final UsuarioFormBeanSingleton instancia = new UsuarioFormBeanSingleton(); 


  public static synchronized UsuarioFormBeanSingleton getInstacia(){  
         return instancia;  
    }

Bom tutorial: http://en.wikipedia.org/wiki/Singleton_pattern

J

Fiz a correção ficando assim, mas ainda não funcionou:

Quando faço isso no início do sistema:

UsuarioFormBeanSingleton usuarioSingleton = UsuarioFormBeanSingleton.getInstacia(); usuarioSingleton.setNome("Francisco"); usuarioSingleton.setCodigo(2008);

Em outra parte do sistema faço isso imprime null:

UsuarioFormBeanSingleton usuarioSingleton = UsuarioFormBeanSingleton.getInstacia(); System.out.println("Nome usuario: "+usuarioSingleton.getNome()); // imprime null

Seria algo com os set e get da classe?

S

javer:
Fiz a correção ficando assim, mas ainda não funcionou:

Quando faço isso no início do sistema:

UsuarioFormBeanSingleton usuarioSingleton = UsuarioFormBeanSingleton.getInstacia(); usuarioSingleton.setNome("Francisco"); usuarioSingleton.setCodigo(2008);

Em outra parte do sistema faço isso imprime null:

UsuarioFormBeanSingleton usuarioSingleton = UsuarioFormBeanSingleton.getInstacia(); System.out.println("Nome usuario: "+usuarioSingleton.getNome()); // imprime null

  1. Um usuário não pode ser singleton : um sistema tem vários usuários
  2. Para quê “UsuarioFormBeanSingleton” e não “Usuario” ?
  3. Vc não precisa de um singleton. Vc precisa de um acesso global.
  4. A sua aplicação é web ? use Session para manter o objeto
  5. Se a sua aplicação é standalone desktop ou em alternativa a 4 use ThreadLocal
    O que vc precisa é deixar o usuário acessivel em qualquer Thread então o melhor é ThreadLocal ou uma das suas subclasses.
V

Coloque uma variavel para controle no UsuarioFormBeanSingleton

private static int contador = 0;

e Adicione uma validação para limitar o numero de instancias que você quer:

public static UsuarioFormBeanSingleton getInstacia(){
    	   if(contador == 0)
    	   {
    		   instancia = new UsuarioFormBeanSingleton();
    		   contador++;
    	   }
    	   else
    	   {
    		   System.out.println("Ja existe uma istancia de UsuarioFormBeanSingleton");
    	   }
    	   return instancia;
      }
J

Pergunta: O que é ThreadLocal?

L

Olá

Além do que o Sérgio Taborda escreveu, eu completo:

  1. Não use Singletons porque impedem testes unitários
  2. Não use Singletons porque complicam o desacoplamento entre as classes
  3. Não use Singletons porque quase nunca são necessários
  4. Não use Singletons porque causam uma má impressão sobre o tanto que você entende de OO e de coisas tais como injeção de dependências por exemplo.

Resumo: Não use Singletons

[]s
Luca

S

Ora , ora … a bilbia explica : http://java.sun.com/javase/6/docs/api/java/lang/ThreadLocal.html
veja tb : http://java.sun.com/javase/6/docs/api/java/lang/InheritableThreadLocal.html

Básicamente é uma forma de associar variáveis à thread. (Thread vc sabe o que é , né? :smiley: )
Todo o codigo que vc executa está sendo executado por uma thread. Não sempre pela mesma, mas a cada execução por uma só. Entenda que a thread é omnipresente no seu codigo. Então, se vc associa um objeto à thread vc está associando variáveis omnipresentes ao seu codigo. Ou seja, vc pode atribuir e retornar o seu valor a qualquer momento.

Claro, na prática a coisa não é tão simples. Por isso depende da sua arquitetura. E por isso existe a InheritableThreadLocal. É que as vezes a sua thread se divide em outras. Os dados não passam para essas threads a menos que tenham sido colocados na thread original com InheritableThreadLocal.

Pense nestas classes como um Map omnipresente mas com uma só chave e valor.

L

cara… precisa de contador nao…

faz assim oh…

private static UsuarioFormBeanSingleton usuario;

private UsuarioFormBeanSingleton() { }

public static UsuarioFormBeanSingleton getInstancia() {

  if (usuario == null) {
    usuario = new UsuarioFormBeanSingleton();
  }
  return usuario;

}
V

Perai, não vamos generalizar, se for assim daqui uns dias vocês estão falando também pra não usar classes internas em swing, “porque causam uma má impressão sobre o tanto que eu entendo de OO”

Vamos lá, o Padrão “Singleton”, “Design Patterns” não foi elaborado pra fuder com as nossas vidas, muito pelo contrario, é uma solução, talves não a mais eficiente, mas basta saber quando, onde e porque utiliza-lo.

http://www.devmedia.com.br/articles/viewcomp.asp?comp=4704&hl=sqlserver

L

Olá

Cite 3 casos em que o uso dos Singletons é fundametal em Java e que não se pode obter uma solução melhor com outra alternativa que não ferre os testes unitários.

Cuidado que este artigo contém idéias que não muito boas e que para mim invalidam TODO seu texto.

[]s
Luca

A

Acho dificil você precisar de singleton como o pessoal já comentou, de qualquer forma, qual a raiz do problema?

Alias, como o sergio comentou, criar um usuario como singleton chega a ser até uma heresia.

V

Luca:
Olá

Cite 3 casos em que o uso dos Singletons é fundametal em Java e que não se pode obter uma solução melhor com outra alternativa que não ferre os testes unitários.

Cuidado que este artigo contém idéias que não muito boas e que para mim invalidam TODO seu texto.

[]s
Luca

Não Luca, não estou falando que singleton é a melhor solução sempre, só falei que não podemos generalizar, “nunca usar singleton”, pô a própria Api da sun utiliza esse Pattern, Apache também, entre outras, sera que os arquitetos dessas empresas são todos burros?

M

Até os Renderers do JSF são Singleton

L

Olá

O problema é que os conceitos MUDARAM. Antigamente ninguém usava injeção de dependências e a prática de testes unitários não era tão obrigatória para selecionar os programadores. Hoje em dia é mais fácil você recomendar fortemente para não usar Singletons do que aturar as conseqüências no projeto de um Singleton mal usado.

E cuidado também que nem sempre os códigos internos do Apache servem de exemplo. Há muito código confuso por lá, mesmo aqueles escritos por não indianos.

[]s
Luca

R

A proposta de utilizar Singleton para reter as informações do usuário foi minha… me desculpem.
Não posso falar pra um iniciante colocar um injeção de dependencia se ele nem entende o que é uma ThreadLocal ainda. Achei que iria enrolar muito o pensamento dele.

Bem, siga as orientações da ThreadLocal ou da Session do sergiotaborda.

Ma bad!

P

Olá,

Falaram de ThreadLocal e fiquei instigado a como se usa então, ao invés do Singleton. Fiz umas buscas na web, e a partir dos exemplos encontrados:

Google InheritableThreadLocal
Threading lightly, Part 3
Caching in repository?

desenvolvi um exemplo, e gostaria de saber se é isso mesmo que sergiotaborda e Luca queriam dizer ao usar InheritedThreadLocal ao inves do puro padrao Singleton.

MyContext.java
package threadlocal;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 *
 */
public class MyContext {
    
    
    private MyContext() {
        //não permite instanciar
    }
    
    private Map<String, Object> map = new HashMap<String, Object>();
   
    protected static InheritableThreadLocal context = new InheritableThreadLocal() {
        @Override
        protected Object initialValue() {
            return new MyContext();
        }
    };
    
    public static MyContext getInstance() {
        return ((MyContext) context.get());
    }

    public Collection<Object> values() {
        return map.values();
    }

    public int size() {
        return map.size();
    }

    public Object remove(String key) {
        return map.remove(key);
    }

    public Object put(String key, Object value) {
        return map.put(key, value);
    }

    public Object get(String key) {
        return map.get(key);
    }

    public boolean containsValue(String value) {
        return map.containsValue(value);
    }

    public boolean containsKey(String key) {
        return map.containsKey(key);
    }

    public void clear() {
        map.clear();
    }
}

Exemplo de uso:

ContextMainSample.java
package threadlocal;

/**
 *
 */
public class ContextMainSample {
    
    public static void main(String []args) {
        ContextMainSample cms = new ContextMainSample();
        cms.carregaNome();
        cms.imprimeNome();
                
    }
    
    
    public void carregaNome() {
        String nome = "Marcos";
        MyContext context = MyContext.getInstance();
        context.put("nome", nome);      
    }
    
    public void imprimeNome() {
        MyContext context = MyContext.getInstance();
        System.out.println(context.get("nome"));
    }
}
Esta certo?

Abracos

S

O espirito é esse , mas vc criou logo um map como objeto da thread. :lol:
Assim vc pode guardar o que quiser na thread usando uma só ThreadLocal. Como teste é isso mesmo. Mas eu me referia a usar uma ThreadLocal que não seja um Map e sem usar o mecanismo de singleton. Mas agora bateu a dúvida se dá para fazer sem usar o mecanismo de singleton…

public static MyContext getInstance() { return ((MyContext) context.get()); }

R

Uso singletons para carregar propriedades JMX, não tenho do que reclamar e não vejo forma mais simples de faze-lo.

L

Olá

  1. O que são propriedades JMX?

  2. Você testa estas classes que usam estas tais “propriedades JMX”?

[]s
Luca

R

Propriedades injetadas via JMX.

Sim, consigo testar.

[]'s

R

Eu tb nunca tive dificuldade para testes com Singleton.
Onde, normalmente, eu teria este problema?

L

Olá

Eu tb nunca tive dificuldade para testes com Singleton.
Onde, normalmente, eu teria este problema?

Como faz testes unitários de uma classe Singleton?Talvez vocês tenham conseguido resolver um problema que muita gente ainda não conseguiu de forma satisfatória.

[]s
Luca

R

Luca:

Como faz testes unitários de uma classe Singleton?Talvez vocês tenham conseguido resolver um problema que muita gente ainda não conseguiu de forma satisfatória.

Ou de repente eu estou fazendo o teste errado por inexperiencia ou falta de visão. E foi por esta duvida que eu lhe perguntei e volto a lhe perguntar: onde há o problema em testar um Singleton?!?

R

Luca:
Olá

Eu tb nunca tive dificuldade para testes com Singleton.
Onde, normalmente, eu teria este problema?

Como faz testes unitários de uma classe Singleton?Talvez vocês tenham conseguido resolver um problema que muita gente ainda não conseguiu de forma satisfatória.

[]s
Luca

verifico se ele carrega e armazena as propriedades corretamente, e ele também é utilizado nos unit tests de classes que necessitam de suas propriedades.

isso não é suficiente ?

se não, por favor, dê exemplos práticos.

[]'s

R

Seguindo a mesma linha do Rafael, e refinando mais os testes automatizados, se vc testar, por exemplo, o seu método de negócio que necessite de informações contidas neste Singleton, vc estará indiretamente testando o próprio Singleton, correto?

V

Só consigo pensar em uma: Quando você precisa de um programa final de tamanho pequeno (e, portanto, não quer sobrecarregar seu usuário com um framework de DI) para um applet ou uma aplicação mobile. Nesse caso provavelmente a aplicação nem terá muitas threads e classloaders mesmo.

Ainda assim, usar o singleton como um repositório de variáveis globais quase nunca é uma boa idéia. Se puder, fuja dele.

A

O problema com a testabilidade dos singletons são a criação de Mocks com teste unitarios. Por exemplo, para testar uma action que faz um consulta em um banco de dados, vc não deve deixar seu DAO se conectar com o banco de dados, pois isto seria um teste de integração e não unitario. A solução para isto é criar um Mock, ou seja, substituir a camada do DAO por um Mock.

Agora imagine que este DAO é um singleton (arg o pior que é tem disto por ai :frowning: ) Como vc iria fazer para substituir o DAO sem mexer no codigo?

Agora imagine que vc esta usando a injeção de dependencia do spring ou mesmo o conjuto PicoContanier + NanoContainer, para substituir o DAO por um mock bastaria alterar uma simples configuração em um XML.

[]'s

V

Um outro detalhe. No livro design patterns, também se referem a código C++.

No C++, algumas característica tornam o uso do singleton mais vantajoso:

  1. C++ não tem um bom mecanismo de reflexão (o que compromete a construção de frameworks de DI);
  2. Não há problemas com multiplos classloaders;
  3. Você elimina a dependencia da classe nos seus headers, o que melhora os tempos de compilação.

Ainda assim, numa aplicação Java comercial comum, não há porque usar singletons hoje em dia. Exceto talvez no caso que eu citei ali (uma restrição forte de equipamento ou tamanho do executável final).

A

Vc utiliza um singleton para ler um properties?? é isto que eu estou entendo?

PS: Como eu faço para escrever “Não sei quem disse” em uma citação?

R

Sim, tenho uma série de propriedades que são gerenciadas via JMX, e a aplicação tem acesso a elas por meio de singletons, que nada mais são do que javabeans contendo estas propriedades.

Isso faz o acesso a essas propriedades muito simples, por isso não entendo o porque de toda essa alergia a singletons.

[]'s

M

ovelha:

PS: Como eu faço para escrever “Não sei quem disse” em uma citação?

Na tag “quote”, coloque o nome: “quote=nomeDeQuemEscreveu”.
Se voce clicar no botão citar, isto vai ser feito automaticamente.

M

também acho estranho o uso de métodos estáticos no FacesContext. Fica muito complicado criar testes para os componentes que acessam o FacesContext.

Apenas reforçando:

cuidado com singletons e métodos estáticos. Os dois dificultam e muito os testes unitários.

V

também acho estranho o uso de métodos estáticos no FacesContext. Fica muito complicado criar testes para os componentes que acessam o FacesContext.

Apenas reforçando:

cuidado com singletons e métodos estáticos. Os dois dificultam e muito os testes unitários.

Bom então o problema não é com o padrão singleton e sim com os testes unitarios? o que deve ser encontrado é uma solução pra testes unitarios.

Oras se o banco x não funciona direito com Java, por que vou trocar o banco? vou trocar o java. rsrsr :twisted:

L

Olá

[]s
Luca

A

Rafaelprp:
Sim, tenho uma série de propriedades que são gerenciadas via JMX, e a aplicação tem acesso a elas por meio de singletons, que nada mais são do que javabeans contendo estas propriedades.

Isso faz o acesso a essas propriedades muito simples, por isso não entendo o porque de toda essa alergia a singletons.

[]'s

http://c2.com/cgi/wiki?SingletonsAreEvil

http://www.guj.com.br/posts/list/14615.java

http://blog.caelum.com.br/2006/08/08/singletons-e-static-perigo-a-vista/

http://forum.java.sun.com/thread.jspa?threadID=749491&messageID=4286396

Bem, isso é tudo que tenho aqui dos meus favoritos, não coloquei algumas paginas como o do shoes pq nao consegui acessar, acho que está off.

Boa leitura pra todos.

M

Não, o problema é que singleton e métodos estáticos aumentam o acoplamento das classes. Quando existe um forte acoplamento, fica difícil criar testes unitários.

Criado 3 de dezembro de 2007
Ultima resposta 5 de dez. de 2007
Respostas 37
Participantes 15