Sobre Singleton

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)?

[code]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;
}    

}[/code]

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?

deixa eu ver se eu entendi:

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

getInstacia() retorna ele mesmo? recursividade?

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

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?

[quote=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

[/quote]

  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.

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;
      }

Pergunta: O que é ThreadLocal?

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

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.

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;

}

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

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

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.

[quote=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[/quote]

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?

Até os Renderers do JSF são Singleton

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

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!

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[code]
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();
}

}
[/code]

Exemplo de uso:

ContextMainSample.java[code]
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"));
}

}
[/code]
Esta certo?

Abracos

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()); }

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