Variaveis redefinidas globais

25 respostas
Guichaguri

Olá, não sei se postei na area correta.

Bom, minha dúvida é a seguinte: Quero fazer variaveis que foram redefinidas que possam ser usadas em outras classes.

Exemplo:

Arquivo Variaveis.java

public class Variaveis {
public int variavel = 2;

public void mudarVariavel() {
variavel = 1;
}

}

Arquivo Global.java

public class Global {
public int numero = new Variaveis().variavel;
}

Eu queria que a variavel “numero” no arquivo “Global.java” interpretasse “1”, e não “2”.

OBS: A função mudarVariavel() já foi usada e não pode ser usada novamente.

Isso é possível? Podem me ajudar?

Obrigado.

25 Respostas

B

O problema é o teu new Variáveis(), ele vai instanciar um objeto novo de Variaveis com os atributos iniciais dele.

Duas formas de resolver isso:

  1. Alterar a variável que será mudada para static, ou seja, essa variável terá o mesmo valor em todas as instancias da classe.
  2. Instanciar Variaveis numa única vez e guardar esse objeto dentro de uma classe global onde um método dela é chamado uma única vez, por exemplo, o método main (public static void main(String[] args)) da classe que inicia o programa. A idéia é o programa instanciar a classe de configurações durante o processo de início do programa, e manter numa memória global.
utluiz

Bruno Laturner:
O problema é o teu new Variáveis(), ele vai instanciar um objeto novo de Variaveis com os atributos iniciais dele.

Duas formas de resolver isso:

  1. Alterar a variável que será mudada para static, ou seja, essa variável terá o mesmo valor em todas as instancias da classe.
  2. Instanciar Variaveis numa única vez e guardar esse objeto dentro de uma classe global onde um método dela é chamado uma única vez, por exemplo, o método main (public static void main(String[] args)) da classe que inicia o programa. A idéia é o programa instanciar a classe de configurações durante o processo de início do programa, e manter numa memória global.


3. chamar o métoto mudarVariavel() no construtor da classe Variaveis.
4. Usar um singleton, que acredito ser o melhor design para elementos “globais”

Ruttmann

utluiz:
Bruno Laturner:
O problema é o teu new Variáveis(), ele vai instanciar um objeto novo de Variaveis com os atributos iniciais dele.

Duas formas de resolver isso:

  1. Alterar a variável que será mudada para static, ou seja, essa variável terá o mesmo valor em todas as instancias da classe.
  2. Instanciar Variaveis numa única vez e guardar esse objeto dentro de uma classe global onde um método dela é chamado uma única vez, por exemplo, o método main (public static void main(String[] args)) da classe que inicia o programa. A idéia é o programa instanciar a classe de configurações durante o processo de início do programa, e manter numa memória global.


3. chamar o métoto mudarVariavel() no construtor da classe Variaveis.
4. Usar um singleton, que acredito ser o melhor design para elementos “globais”

Concordo com o Luiz!

É muito mais performático o uso de Singleton do que a prática de tornar a variável um atributo static

Com os dois você vai conseguir o mesmo resultado, obviamente…

Mas com o uso de Singleton na classe da variável, você assegura que só existirá uma instância da classe citada, evitando múltiplas instâncias da mesma classe que não vão servir pra nada, só pra lotar a memória…

rmendes08

Na verdade o problema são as próprias variáveis globais. Veja só, só de tentar simular o conceito de variáveis globais em Java você está com dificuldades, imagine o inferno que seria debugar um sistema com algun milhares de linhas de código e com dezenas de trheads lendo e escrevendo essas variáveis …

Na boa mesmo, faça um esforço para mudar seu mindset e tente aplicar OO. Você pode sofrer um pouco no começo, mas vale bastante a pena.

utluiz

rmendes08:
Na verdade o problema são as próprias variáveis globais. Veja só, só de tentar simular o conceito de variáveis globais em Java você está com dificuldades, imagine o inferno que seria debugar um sistema com algun milhares de linhas de código e com dezenas de trheads lendo e escrevendo essas variáveis …

Na boa mesmo, faça um esforço para mudar seu mindset e tente aplicar OO. Você pode sofrer um pouco no começo, mas vale bastante a pena.

Concordo, inclusive o uso do pattern Singleton vai nesse sentido.
Num cenário multi-thread, uma classe singleton com o devido encapsulamento permitiria sincronizar o acesso simultâneo aos dados.

ViniGodoy

Atenção: Singleton não é um pattern para criar coisas globais.
Usa-lo para isso é gambiarra, é a razão pelo qual o pattern hoje é considerado por muitos um anti-pattern.

Singleton é um pattern para se criar uma única instância de um objeto. Se esse não é o seu objetivo, então, não use singleton.
Na verdade, variáveis globais são uma aberração da natureza e, salvo raríssimas exceções, são inúteis.

Não use globais. Elas farão você caminhar com dor, pânico e desespero pelo vale da sombra da morte.
Variáveis globais contribuem para um código estruturado, tornam a vida difícil em ambientes multi-thread, tornam o sistema instável e difícil de depurar.

A única coisa que pode ficar global é constante. No caso de objetos, para ser considerado uma constante, o objeto também deve ser imutável.

Rodrigo_Sasaki

Realmente, quem que já mexeu com variáveis globais que nunca sentiu aquele pânico:

“O que será que vai acontecer com o resto do sistema se eu alterar ela aqui nesse ponto?”

B

“O que vai acontecer com o resto do meu sistema se eu trazer o Cliente com id 1234 do banco de dados e mudar o nome dele?”

Acho que estão complicando demais. :smiley:

utluiz

ViniGodoy:
Atenção: Singleton não é um pattern para criar coisas globais.
Usa-lo para isso é gambiarra, é a razão pelo qual o pattern hoje é considerado por muitos um anti-pattern.

Singleton é um pattern para se criar uma única instância de um objeto. Se esse não é o seu objetivo, então, não use singleton.
Na verdade, variáveis globais são uma aberração da natureza e, salvo raríssimas exceções, são inúteis.

Não use globais. Elas farão você caminhar com dor, pânico e desespero pelo vale da sombra da morte.
Variáveis globais contribuem para um código estruturado, tornam a vida difícil em ambientes multi-thread, tornam o sistema instável e difícil de depurar.

A única coisa que pode ficar global é constante. No caso de objetos, para ser considerado uma constante, o objeto também deve ser imutável.

Tudo isso depende do ponto de vista.
Existe realmente uma diferença entre um objeto global e um objeto único? Pra mim é apenas uma questão de nomenclatura, ambos os casos podem levar a implementações ruins.
Mas uma má implementação do singleton, na minha opinião, nunca será motivo suficiente para considerá-lo um anti-pattern, pois em ele é extremamente útil e necessário em algumas situações e também é utilizado em diversos frameworks conhecidos, principalmente relacionados a logging.

Uma situação bem simples, que cabe no exemplo do Guichaguri, é um arquivo de dados local carregado para um javabean, por exemplo, configurações de um aplicativo.

O maior problema com os singletons, segundo alguns autores, é usá-lo para recuperar instâncias de classes de um sistema mantendo referências estáticas. Para esses casos seria melhor usar inversão de controle ou pelo menos factories.

ViniGodoy

utluiz:
Tudo isso depende do ponto de vista.
Existe realmente uma diferença entre um objeto global e um objeto único? Pra mim é apenas uma questão de nomenclatura, ambos os casos podem levar a implementações ruins.

Existem pelo menos duas:

  1. Um objeto pode ser global e não ser único (podem haver outras instâncias dele pelo sistema);
  2. Um objeto único não precisa estar no escopo global: ele pode estar dentro só de um pacote;

Qual framework? Nem o java.util.logging e nem o Log4J fazem isso. Poderia citar um framework sério que use singleton?
E outra, pode citar um framework sério que a decisão de projeto de tornar algo singleton é simplesmente o fato de “criar um repositório para variáveis globais”?

Variável global não deixa de ser gambi por estar dentro de um singleton.

E por que não pode usar para isso o Registry? Ou mesmo criar uma instância local, ler os dados e depois descarta-la? Não vejo qualquer motivo para que isso seja singleton.

Outro problema é que é difícil garantir que o singleton se mantenha singleton (especialmente em servidores web, com múltiplos classloaders ou em ambientes com múltiplas threads);
Outro problema é o fato de variáveis estáticas serem fontes de memory leak.
Outro problema é o fato de singletons serem serializadores de threads.
Outro problema é o fato do singleton se difícil de refatorar, difícil de adaptar, difícil de testar.

O Singleton, na minha opinião, só é válido quando você tem um sistema desktop e monolítico, onde as threads estejam sob seu controle, onde tenha um só classloader. É o caso de games, que infelizmente, não são o tipo de sistema que se faz em Java. Eu até defendo o padrão singleton nesses casos. Porém, desde que você use o singleton para fazer o que ele foi feito para fazer.

utluiz

ViniGodoy:
utluiz:
Tudo isso depende do ponto de vista.
Existe realmente uma diferença entre um objeto global e um objeto único? Pra mim é apenas uma questão de nomenclatura, ambos os casos podem levar a implementações ruins.

Existem pelo menos duas:

  1. Um objeto pode ser global e não ser único (podem haver outras instâncias dele pelo sistema);
  2. Um objeto único não precisa estar no escopo global: ele pode estar dentro só de um pacote;

Essa diferença existe com certas suposições implícitas.
Um objeto global e não único provavelmente vai ter uma identificação única. Logo, ele é único dentro de um escopo.
Por exemplo: meu programa deve ler dados de uma tabela no oracle e popular uma tabela no mysql através de um DAO único, logo terei 2 instâncias, mas cada uma delas funcionará como um singleton para cada banco.

Qual framework? Nem o java.util.logging e nem o Log4J fazem isso. Poderia citar um framework sério que use singleton?
E outra, pode citar um framework sério que a decisão de projeto de tornar algo singleton é simplesmente o fato de “criar um repositório para variáveis globais”?
Pesquise por “singleton” nesse link: http://wiki.apache.org/logging-log4j/Log4JStatic
LocalThread é usado em inumeráveis frameworks e funciona basicamente como um singleton para a thread.
ResourceBundle retorna um singleton.

Troque “variável global” por “parâmetro global” ou “recurso global”, lembrando que ambos podem ser variáveis.

E por que não pode usar para isso o Registry? Ou mesmo criar uma instância local, ler os dados e depois descarta-la? Não vejo qualquer motivo para que isso seja singleton.
O pattern Registry? A diferença não é que ao invés de um único objeto global você terá um mapa de objetos globais? Um mapa de singletons é melhor que um singleton?

Outro problema é que é difícil garantir que o singleton se mantenha singleton (especialmente em servidores web, com múltiplos classloaders ou em ambientes com múltiplas threads);
Outro problema é o fato de variáveis estáticas serem fontes de memory leak.
Outro problema é o fato de singletons serem serializadores de threads.
Outro problema é o fato do singleton se difícil de refatorar, difícil de adaptar, difícil de testar.
Sim, mas existem requisitos de software que podem exigir alguns desses “problemas”. Qualquer pattern só é bom ou ruim dependendo dos requisitos do projeto, dificilmente podemos fazer uma afirmação de forma absoluta.

Ou quando o sistema depende de um recurso único e compartilhado (arquivo, conexão).

Enfim, como o Bruno disse, acho que estamos complicando demais. A questão inicial já foi bem respondida.
Encerro minha participação neste tópico e agradeço a todos porque aprendi várias coisas hoje.

ViniGodoy

“Singleton por thread” != singleton. O padrão singleton é bem claro ao limitar a uma única instância. Se tem mais de uma instância, não é singleton. Como o SergioTaborda uma vez definiu, o singleton é o “highlander” do sistema. “There can be only one”.

No caso do threadlocal, existe mais de uma instância. A construção é garantida pela VM, há muita implementação e muita verificação para garantir que ele crie uma instância no escopo de várias threads (um dos grandes problemas do Singleton). Além disso, o ThreadLocal não dá garantias de múltiplos classloaders, e nem se preocupa com isso, pois ela não promete um singleton.

Finalmente, não vi você recomendando um threadlocal, e sim, um singleton.

Essa diferença existe com certas suposições implícitas.
Um objeto global e não único provavelmente vai ter uma identificação única. Logo, ele é único dentro de um escopo.
Por exemplo: meu programa deve ler dados de uma tabela no oracle e popular uma tabela no mysql através de um DAO único, logo terei 2 instâncias, mas cada uma delas funcionará como um singleton para cada banco.

Essas suposições é você quem está criando. Não existem suposições implícitas. Um objeto global é só um objeto colocado num local acessível por todos. Pode ou não ter o mesmo id de outros objetos. Um singleton é um objeto em que se quer controlar a instanciação, para limita-la a uma única instância. Qualquer coisa diferente disso, não é singleton.

Troque "variável global" por "parâmetro global" ou "recurso global", lembrando que ambos podem ser variáveis.

E todos continuam sendo gambiarra.

Não, essa não passa nem perto da definição de registry. O registry é um objeto de fácil acesso, onde você pode a partir dele acessar outros objetos. O registry não precisa ser singleton, não precisa ser global, e nem tem obrigação de retornar instâncias únicas.

Quanto ao link que você indicou, diz que:
“Log4J can return singleton instances but it is not a rule!”

Além disso, o Log4J não recomenda essa prática. Na versão 0.8.0, ele foi especificamente modificado para não depender do Singleton, devido aos problemas que isso causava:
“As of release 0.8.0, the syntax was further modified so that log statements (debug, info, … methods) no longer need a log singleton but use a Category instance instead.”
http://www.jajakarta.org/log4j/jakarta-log4j-1.1.3/docs/FAQ.html

Exatamente, foi como eu falei: O singleton deve ser usado para garantir que um objeto é único. Não simplesmente como repositório de variáveis globais, que foi a razão que você apontou no primeiro post.

utluiz

Desculpe, mas vou precisar comentar. Prometo que será a última vez… :wink:

ViniGodoy, você pegou uma citação genérica que eu fiz a respeito de “elementos” e “dados” para dizer que eu estou defendendo o uso do singleton para repositório de variáveis globais. Independendo do que isso queira dizer, qual seria então a solução genérica mais adequada para armazenar valores mutáveis de parâmetros ou configurações usados por aplicações de qualquer tipo de forma desacoplada?

Além disso, você se baseia em definições que não são unânimes. Um objeto único por thread pode ser um singleton, sim, dentro de um escopo. O escopo é essencial para essa definição, caso contrário, eu não poderia afirmar que existe um único singleton sequer, já que qualquer outra JVM no mundo pode ter uma outra instância das classes que eu uso no meu sistema.

A minha definição de singleton é a de um objeto único dentro de um escopo. Se a implementação disso usa um membro estático de nome “instance” e um método “getInstance()” sincronizado isso não faz diferença, porque o efeito de objeto único é o mesmo e todas as vantagens, desvantagens e riscos acompanham essa implementação em menor ou maior grau.

O que dizer das anotações @Singleton que alguns frameworks trazem? Elas usam qual definição de singleton? Elas estão erradas em usar essa terminologia?

Se a vantagem do threadlocal é ter várias garantias e verificações, então bastaria usar um framework singleton para resolver o problema.

ViniGodoy

As definições não são informais, são bem formais e são, sim, unânimes. São definidas em livro ou material de referência. No caso do Singleton, esse livro é o Design Patterns, Elements of Reusable Object Oriented Software. Não existe isso de “minha definição” ou “minha opinião” aqui. O objetivo primordial dos design patterns é criar um catálogo de soluções conhecidas e homologadas. Se você muda o pattern, não é mais o pattern.

O pattern também não se refere a implementação, mas a funcionalidade. É um pattern de “design”. Você não precisa de um método getInstance para ter um singleton. O objetivo do pattern é criar uma instância única. E por única, ele quer dizer única mesmo.

A anotação @Singleton tenta emular essa funcionalidade. E precisa de um complexo mecanismo para garantir isso num servidor EJB.

O que eu critiquei é justamente sua frase, por ser simplista. Você disse somente:

Você falou assim, seco, sem dar qualquer detalhes da implicação disso, sem dizer que o Singleton era para outras coisas. Da forma que você colocou, soou que essa era uma decisão óbvia de design e, não só isso, uma excelente decisão.

Você também não disse que o Singleton é uma possível opção, mas sim, a “melhor opção” para “elementos globais”. O que há para não entender aqui? E o que tem de genérico na frase? Você simplesmente afirmou, com todas as letras e categoricamente, que esse é o “melhor pattern para elementos globais”. Por isso veio a minha crítica logo em seguida, pois num fórum de Java Básico, uma afirmação simplista como essa pode estimular o uso do padrão, onde ele não deveria ser estimulado.

Minha sugestão é fazer o que já foi dito pelo rmendes08. Rever a necessidade de globais. Na maior parte dos casos, elas sequer precisam ser globais, podem ser acessadas de um contexto local. Em muitos casos, basta ter um registry num local mais acessível, e você passa a obter os mesmos benefícios do Singleton sem os seus malefícios.

Não estou criticando a existência do pattern, só o fato de sua frase ter dado a entender que ele é o melhor local para se colocar elementos globais. O fato de ser global deveria ter pouco a ver com sua decisão de usar um singleton. A razão pela qual você deveria querer um singleton é o fato dele ser único. É muito mais difícil dar essa última garantia.

PS: Na verdade, se você olhar meu primeiro post, vai ver que nem sequer citei sua frase especificamente, só coloquei a ressalva de que não era o propósito do pattern ser um repositório de variáveis globais.

utluiz

Vini, antes de mais nada tenho que concordar com você sobre minha colocação simplista.
Estava focado apenas na questão e não enxerguei as consequências da minha afirmação genérica, o que não foi minha intenção. Se eu pretendesse ser categórico e definitivo, teria dado evidências para provar meu ponto de vista. A partir de agora vou tentar limitar o escopo das minhas afirmações.

Design Patterns (GoF) > Singleton > Consequences

4. Permits a variable number of instances. The pattern makes it easy to change your mind and allow
more than one instance of the Singleton class. Moreover, you can use the same approach to
control the number of instances that the application uses. Only the operation that grants access to
the Singleton instance needs to change.

Design Patterns (GoF) > Singleton > Implementation

A more flexible approach uses a registry of singletons. Instead of having Instance define the
set of possible Singleton classes, the Singleton classes can register their singleton instance by
name in a well-known registry.

Guichaguri

Olá, vocês podem me dar um exemplo sobre algum desses modos em java? Como por exemplo esse tal de Singleton…

Sou novato em java, só quero um jeito simples pra isso.

OBSERVAÇÃO: O sistema é para um servidor com vários eventos, funções e etc. Quero poder usar essas variaveis em eventos.

Obrigado.

utluiz

Guichaguri, antes de mais nada, quero evitar confusão e recolocar minha principal sugestão conforme minha intenção inicial:
4. Usar um singleton, que para o exemplo de código em questão, acredito ser o melhor design para resolver o problema dos elementos “globais”

Tendo dito isto, se seu programa fosse para funcionamento no cliente, num ambiente com pouca complexidade, essa solução seria a mais vantajosa. Uma implementação simples, sem preocupação com acesso simultâneo, seria:

//Classe com pattern Singleton para garantir uma instância
public class Variaveis {  

  //referência para a instância única
  private static Variaveis instance;

  //recupera a instância, criando no primeiro acesso
  public static getInstance() {
    if (instance == null) {
      instance = new Variaveis();
    }
    return instance;
  }

  //variáveis encapsuladas
  private int variavel;
  
  //inicialização das variáveis num construtor privado para evitar que outras classes criem instâncias indesejadas
  private Variaveis() {
    variavel = 2
  }

  //método que altera a variável
  public void mudarVariavel() {  
    variavel = 1;  
  }  
  
  //recuperar valor de variável com encapsulamento
  public int getVariavel() {
    return variavel;
  }
}  

public class Global {  
  public int numero = Variaveis().getInstance().getVariavel();  
}

Porém, se você vai colocar esse código num servidor JEE, o cenário muda completamente.
Nesse caso, você deve evitar ao máximo usar objetos globais ou de instância única ainda que seja num numa mesma classe, pois deve considerar que mais de um usuário pode acessar o sistema ao mesmo tempo e comportamentos estranhos podem surgir.
Se for mesmo um servidor JEE e você está começando talvez com JSP e Servlets, coloque uma instância da classe Variavel na sessão do usuário logo de início e recupere de lá sempre que precisar.
Se estiver usando um framework diferente, então nos informe para que possamos ajudar melhor.

Enfim, padrões como o Singleton podem ser bons ou ruins dependendo do contexto. Todos os padrões possuem vantagens, desvantagens e riscos (ou simplesmente consequências) e, por esta razão nunca podemos afirmar categoricamente que são uma boa ou má escolha sem conhecer o contexto.

Guichaguri

Hm…

E como seriam os outros jeitos ?

Pode me passar um exemplo?

Guichaguri

Bom, é o que eu acho melhor e mais fácil pra mim: Usar uma classe pra ficar as variáveis globais.

rmendes08

Guichaguri:
Hm…

E como seriam os outros jeitos ?

Pode me passar um exemplo?

Cara, é difícil sugerir alguma coisa sem entender o contexto. Como regra geral eu sempre uso variáveis com o escopo mais restrito possível. Ou seja, sempre que posso, uso variáveis locais. Somente uso variáveis de instância quando não tem outro jeito, ou quando eu preciso efetivamente armazenar o estado de um objeto. Variáveis “globais” nunca. E pode acreditar, é perfeitamente possível e recomendável viver sem elas.

Sendo assim, se você postar pelo menos 1 exemplo do porque você quer usar variáveis globais, ficaria muito mais fácil ajudar.

Guichaguri

Achei uma solução boa e fácil!

// CLASSE PRINCIPAL, A QUE INICIA TUDO E A QUE TEM VARIAVEIS GLOBAIS
public class Principal() {

public int variavelGlobal = 2;

public void ChamarOutraClasse() {
variavelGlobal = 4;
new OutraClasse(this);
}

}

// Outra Classe que vai ser chamada pela classe principal
public class OutraClasse() {

private transient final Principal principal;

// CONSTRUTOR
public void OutraClasse(final Principal principal) {
this.principal = principal;
}

public void OutraFuncao() {
int variavel = principal.variavelGlobal; // 4 :D
}

// Chamando outra classe fora da principal
public void ChamandoMaisOutraClasse() {
new MaisOutraClasse(principal);
}

}

Essa foi a minha solução, não testei ainda, mas tenho a previsão que dê certo.
Acham que vai dar certo?


EDIT: Respondendo o rmendes08, na minha classe principal há uma array que armazena informações temporarias, que vão ser usadas e descartadas logo depois de um tempo, pra a array não “resetar” a cada “new” precisava das variaveis globais.

Mas acho que já resolvi…

rmendes08

Cara, se tiver mais de uma thread acessando a sua classe principal, você já vai ter um baita de um problema. Se o sistema que estive construindo for um sistema de verdade, logo ele vai crescer, e manutenção rapidamente vira um parto. Além do mais, você ainda não colocou o código real, fique tranquilo, ninguém vai roubar a sua idéia, muito provavelmente alguém já teve uma igual … mas enfim, se você não quer ser ajudado, seja feliz …

Guichaguri

Bom, então o que tenho que fazer ?

Do jeito mais bagunçado?

new OutraClasse(variavel1, variavel2);

//////////////////////////

public class OutraClasse {
private final String variavel1;
private final int variavel2;

OutraClasse(String variavel1, int variavel2) {
this.variavel1 = variavel1;
this.variavel2 = variavel2;
}

}

Meu projeto nem é um projeto mesmo, só é um add-on pra um sistema de server de um jogo, só quero que outras classes consigam ler as variaveis da classe principal (mesmo depois de serem mudadas), sem precisar escrever arquivos ou coisas do tipo pra guardar as informações.

Tem como ou vou precisar guardar em um arquivo?

rmendes08

Cara, faça assim. Use a sua classe Principal com variáveis públicas mesmo … se funcionar ótimo, melhor para você, caso contrário, volte e nos conte o que deu errado.

utluiz

Isso mesmo, se não der certo, nos informe mais detalhes sobre a arquitetura desse servidor.
Se ele é aberto para envio de código, provavelmente há algum padrão definido para esse tipo de coisa.

Criado 23 de setembro de 2012
Ultima resposta 27 de set. de 2012
Respostas 25
Participantes 7