Estamos salvos!
Singleton Detector
12 Respostas
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
OláBem observado, editei o post dele para fazer como você sugeriu.
[]s
Luca
Foi malz cliquei no botão errado e nem reparei! :oops: (Sabe como é postar em horário de serviço)
Eu não entendo do domínio mas tenho a impressão que a coesão no seu Singleton é bem baixa.
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 
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…

Singleton não éuma forma de implementar uma variável global?
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.
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.Vamos tentar um exemplo. Imagine o código:
MeuSingleton a = MeuSignleton.getInstance();
/code]
Agora vamos criar uma nova classe:
[code]
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.
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.
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á?
Vamos tentar um exemplo. Imagine o código:MeuSingleton a = MeuSignleton.getInstance(); /code] Agora vamos criar uma nova classe: [code] 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?
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();
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.
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!
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á?
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?
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.
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 