Estamos salvos!
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
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…
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