Singleton Detector

Estamos salvos!

http://code.google.com/p/google-singleton-detector/

Fabio,

Quem vai adorar isso é o Shoes. hehehe!

Fico até triste quando vejo vocês falando tão mal assim do tadinho do Singleton! rs…

Até concordo que o uso excessivo é muito ruim, mas tem horas que ele ajuda muito.

O que vocês acham? Singleton para vocês nunca mais?

Estava montado uma estrutura de classes para facilitar a construção de janelas com componentes HAVI para XLETS. Nesta estrutura eu criei um singleton!

Implementei um SeviceLocator singleton abstrato para o ambiente. Desta forma eu posso criar ambientes concretos para injetar as dependências no ambiente abstrato. Mas continuo tendo uma ambiente abstrato singleton isso é muito ruim? Tá muito ruim? Tem alguma forma melhor de fazer isso?

public class AbstractSingletonControleInvertido {
	
	protected AbstractSingletonControleInvertido(){
		super();
	}
	
	protected static <T> T getInstancia(T _instancia){	

		if(_instancia == null){
			throw new SingletonNaoCarregadoException("Carregue o singleton! " +
					"Utilize o método carregarInstancia() da classe singleton " +
					"a ser utilizada.");
		}
		
		return _instancia; 
	}
			
}


public abstract class AbstractAmbiente extends AbstractSingletonControleInvertido{
	
	private static AbstractAmbiente instancia;
	
	private XletContext contexto;
	private HScene cena;
	private AbstractFacImagensJanela facImagensJanela; 
	
	protected AbstractAmbiente(XletContext _contexto) {
		super();
		contexto = _contexto;
		carregaAmbiente();
	}
	
	public static AbstractAmbiente getInstancia(){
		return getInstancia(instancia);
	}
		
	public abstract HScene carregaCena();
	
	public abstract AbstractFacImagensJanela carregaFacImagensJanela();

	final public XletContext getContexto() {
		return contexto;
	}

	final public HScene getCena() {
		return cena;
	}

	final public AbstractFacImagensJanela getFacImagensJanela() {
		return facImagensJanela;
	}
	
	final public void finalizarAmbiente(){
		new OperacaoSaida().executar();
	}
	
	protected static void setInstancia(AbstractAmbiente _instancia) {
		instancia = _instancia;
	}
	
	private void carregaAmbiente(){
		cena = carregaCena();
		facImagensJanela = carregaFacImagensJanela();
	}

}


public class AmbientePadrao extends AbstractAmbiente{
		
	private AmbientePadrao(XletContext _contexto) {
		super(_contexto);
	}

	public HScene carregaCena() {
		HScene cenaL;
		
		HSceneFactory hsceneFactory = HSceneFactory.getInstance();
		cenaL = hsceneFactory.getFullScreenScene(HScreen.getDefaultHScreen().getDefaultHGraphicsDevice());
		cenaL.setLayout(null);
		cenaL.setVisible(true);
        cenaL.requestFocus();
		
		return cenaL; 
	}

	public AbstractFacImagensJanela carregaFacImagensJanela() {
		return new FacImagensJanelaPadrao();
	}
	
	public static void carregaInstancia(XletContext _contexto){
		setInstancia(new AmbientePadrao(_contexto));
	}

}

Aguardo suas opiniões.

[]s

brunohansen quando colocar seu codigo use Code e não Quote

Olhe a diferença:

protected AbstractAmbiente(XletContext _contexto) {
    super();
    contexto = _contexto;
    carregaAmbiente();
}

Eu não entendo do domínio mas tenho a impressão que a coesão no seu Singleton é bem baixa.

Mas este ainda não é o pior problema, por que este Singleton não pode ser substituído por (1)Uma factory que retorna apenas a mesma instância ou (2) Dependency Injection?

Olá

Bem observado, editei o post dele para fazer como você sugeriu.

[]s
Luca

[quote=Luca]Olá

Bem observado, editei o post dele para fazer como você sugeriu.

[]s
Luca[/quote]

Foi malz cliquei no botão errado e nem reparei! :oops: (Sabe como é postar em horário de serviço)

[quote=pcalcado]Eu não entendo do domínio mas tenho a impressão que a coesão no seu Singleton é bem baixa.
[/quote]

Rs… É pode ser, mas preferi colocar as 3 coisas no mesmo lugar para facilitar criar ambientes.

Estou um pouco confuso em relação ao foi dito, mas… (Entendi menos ainda quando você disse: “…que retorna apenas a mesma instância…” )

Digamos que tivesse uma fábrica das coisas do ambiente, eu teria o mesmo problema para encontrar a fábrica que esta configurada para eu usar. Da mesma forma me pareceria um singleton (Fazer injeção de dependência na mão daria muito trabalho)

Acho que estou destruindo o post inicial (Desculpa ae pessoal), se alguém puder mover o que está relacionado com a minha dúvida para outro tópico derrepente seria melhor.

Valeu ae pessoal pela ajuda!

Sim, sabemos disso. O ponto é que você não precisa de um Singleton, precisa de uma variável global. O que eu estou sugerindo é uma global que minimiza o problema de usar o Singleton (testabilidade e extensibilidade, por exemplo). É a melhor solução? Não. A melhor solução é acabar com a necessidade da global. Enquanto você trabalha no problema de como fazer IoC neste caso a idéia é pelo menos minimizar os efeitos do design atual :wink:

Singleton não éuma forma de implementar uma variável global?

Acho que a forma que eu fiz oferece testabilidade e extensibilidade, pois posso fazer um ambiente herdar de AbstractAmbiente e registralo em AbstractAmbiente. Dá mesmas forma posso criar um mock para fazer teste.

Ainda não pesquei como posso minimizar os efeitos do design atual…

:cry:

Não. Singleton é um objeto que só pode ser instanciado uma vez. Se isntanciar mais de uma vez seu sistema está num estado inválido.

O fato de um Singleton geralmente ter uma variável global expressa na forma de um método estático para obtêr uma instância é uma consequência, e é só isso que você parece precisar.

Vamos tentar um exemplo. Imagine o código:

[code]
MeuSingleton a = MeuSignleton.getInstance();
/code]

Agora vamos criar uma nova classe:

class OutroSingleton extends MeuSingleton{...

Como eu faço o primeiro código usar OutroSingleton ao invés da classe-pai? Quantos lugares eu teria que mudar num sistema real?

Outra coisa: como você cria um teste unitário para uma variável global? Seus testes estarão compartilhando o mesmo recurso (o Singleton) e serão dependentes um do outro, o que é bem ruim. Imagine:

public void testAlgumaCoisa(){
 Singleton s = Singleton.getInstance();
 s.setCoisa("lala");
 assertTrue(s.executaAquelaTarefa());
}

public void testAlgumaOutraCoisa(){
 Singleton s = Singleton.getInstance();
 s.setCoisa(null);
 assertFalse(s.executaAquelaTarefa());
}

Como a classe é uma variável global os dois testes são mutuamente dependentes.

Em relação ao singleton você tem toda a razâo. Acho que meu problema me fez descuidar do conceito do singleton!

Porém, pensando melhor Eu devo ter somente uma única cena, um único contexto e uma única FacImgensJanela! No meu caso, não faz sentido eu ter vários contextos, cenas, facsImagensJanela para um mesmo ambiente. Será que desta forma o singleton pode continuar onde está?

Eu faço assim: O MeuSingleton tem o atributo estático e o método para recuperar a instância (getInstance()); O OutroSingleton tem o método que carrega sua instância para o MeuSingleton (Isto é o que meu código que eu postei lá em cima faz: O AmbientePadão carrega sua instancia para o AbstractAmbiente).

Seu código ficaria assim:


//Em algum lugar você carrega o singleton que você vai usar
OutroSingleton.carregarInstancia();

/*
Onde você usa meu Singleton no seu sistema continua a mesma coisa, pois o OutroSingleton herda de MeuSingleton e se registra como instancia de MeuSingleton
*/
MeuSingleton a = MeuSignleton.getInstance();

[quote=pcalcado]
Outra coisa: como você cria um teste unitário para uma variável global? Seus testes estarão compartilhando o mesmo recurso (o Singleton) e serão dependentes um do outro, o que é bem ruim. Imagine:

public void testAlgumaCoisa(){
 Singleton s = Singleton.getInstance();
 s.setCoisa("lala");
 assertTrue(s.executaAquelaTarefa());
}

public void testAlgumaOutraCoisa(){
 Singleton s = Singleton.getInstance();
 s.setCoisa(null);
 assertFalse(s.executaAquelaTarefa());
}

Como a classe é uma variável global os dois testes são mutuamente dependentes.[/quote]

Outra vez você tem razão! Um exemplo vale por mil palavras!
Um gatilho seria isolar os métodos de teste e assim torna-los independentes.

public void testAlgumaCoisa(){
syscronize(TestAlgo.class){
 carregarAmbienteTeste();
 Singleton s = Singleton.getInstance();
 s.setCoisa("lala");
 assertTrue(s.executaAquelaTarefa());
}
}

public void testAlgumaOutraCoisa(){
syscronize(TestAlgo.class){
 carregarAmbienteTeste();
 Singleton s = Singleton.getInstance();
 s.setCoisa(null);
 assertFalse(s.executaAquelaTarefa());
}
}

Só mais uma dúvida!

Para eu minimizar meu uso do singleton!

Eu poderia criar um Registry, o fazendo ser um ponto único global onde eu acho as coisas, e registrar meu contexto, minha cena e minha facImagensJanela neste singleton. Esta seria uma forma de minimizar?

Valew pela ajuda Shoes!

[quote=brunohansen]Porém, pensando melhor Eu devo ter somente uma única cena, um único contexto e uma única FacImgensJanela! No meu caso, não faz sentido eu ter vários contextos, cenas, facsImagensJanela para um mesmo ambiente. Será que desta forma o singleton pode continuar onde está?
[/quote]

Coincidentemente o padrão Singleton oferce um comportamento parecido com o que você quer, mas o que você quer não é um Singleton. Vale a pena abrir mão do que se precisa para ter um Singleton quando se pode ter uma Factory como comentei? Geralmente não pelos problemas que estamos discutindo abaixo.

Me expressei mal: como eu faço para usar um no lugar do outro. Vamos supor que o novo Singleton possui recursos de segurança implementados via AOP por um framework oua mão mesmo, como eu faço para que meu código trabalhe com esta versão ‘turbinada’ em alguns casos e com a versão normal em outros? Em suma: como eu uso polimorfismo?

[quote=brunohansen]
Outra vez você tem razão! Um exemplo vale por mil palavras!
Um gatilho seria isolar os métodos de teste e assim torna-los independentes.[/quote]

Seu pensamento está na linha correta mas sincronizar os testes é ruim, principalmente porque você vai perder performance (imagina executar 100 testes durante o build com 1 segundo cada).

Seria sim. Só cuidado para o Registry não virar seu novo problema :wink: