Singleton - qual a melhor implementação?

Como exercicio académico apenas. Mas lembra do Waterfall ? Também era apenas um exercicio acadêmico para explicar “como não fazer” e virou padrão de uso. O sigleton com DCL seguiu mesmo caminho.
Sempre deve existir o aviso “Manipule com cuidado: Destinado a fins Acadêmicos” :slight_smile:

[quote=ECO2004]Se eu não usar volatile, o que pode acontecer?
Para mim não haveria mudança, pois a criação do objeto está protegida em um bloco sincronizado.[/quote]

A criação sim, mas o primeiro if que checa se existe, não. E é ali que está o problema. Sem o volatile não é garantido que quando a primeira thread seta a variável no bloco de construção, a segunda leia esse valor no if.
O volatile força o “acesso sequencial” à variável, o que significa que quando a segunda thread for ler, ela irá ler o valor correto que a primeira colocou lá.

Como exercicio académico apenas. Mas lembra do Waterfall ? Também era apenas um exercicio acadêmico para explicar “como não fazer” e virou padrão de uso. O sigleton com DCL seguiu mesmo caminho.
Sempre deve existir o aviso “Manipule com cuidado: Destinado a fins Acadêmicos” :)[/quote]

Não acredito que singletons se aplique somente a fins acadêmicos. No java realmente não faz mais sentido usa-los pois existe a Injeção de Dependência, porém em outras linguagens o uso pode ser valido! Mas sempre com moderação! Singletons não é algo que se deva ficar espalhando pelo projeto!

Como exercicio académico apenas. Mas lembra do Waterfall ? Também era apenas um exercicio acadêmico para explicar “como não fazer” e virou padrão de uso. O sigleton com DCL seguiu mesmo caminho.
Sempre deve existir o aviso “Manipule com cuidado: Destinado a fins Acadêmicos” :)[/quote]

Não acredito que singletons se aplique somente a fins acadêmicos. No java realmente não faz mais sentido usa-los pois existe a Injeção de Dependência, porém em outras linguagens o uso pode ser valido! Mas sempre com moderação! Singletons não é algo que se deva ficar espalhando pelo projeto![/quote]

concordo com vc. o termo "Acadêmico’ referia-se ao "double checked locking " e não ao singleton em si.

[quote=sergiotaborda][quote=ECO2004]Se eu não usar volatile, o que pode acontecer?
Para mim não haveria mudança, pois a criação do objeto está protegida em um bloco sincronizado.[/quote]

A criação sim, mas o primeiro if que checa se existe, não. E é ali que está o problema. Sem o volatile não é garantido que quando a primeira thread seta a variável no bloco de construção, a segunda leia esse valor no if.
O volatile força o “acesso sequencial” à variável, o que significa que quando a segunda thread for ler, ela irá ler o valor correto que a primeira colocou lá.
[/quote]

Valeu pela explicação!

[quote=ECO2004]Pessoal, por que em um singleton que usa “trava dupla”, a variável do tipo da classe tem que usar a palavra reservada volatile?
Que eu saiba, essa palavra é utiliza quando não se deseja persistir a informação.[/quote]

O double checked locking não só deixa o código extremamente complicado, como também não funciona:


http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
http://www.javaworld.com/javaworld/jw-02-2001/jw-0209-double.html (escrito pelo Brian Goetz, criador da linguagem)

Na minha opinião a melhor maneira de se usar um singleton é essa:

[code]public enum Age {
INSTANCE;
private int age;

public int getAge() {
    return age;
}

}[/code]

Simples e rápido, mas você não consegue recuperar .class.

[quote=juliocbq]Na minha opinião a melhor maneira de se usar um singleton é essa:

[code]public enum Age {
INSTANCE;
private int age;

public int getAge() {
    return age;
}

}[/code]

Simples e rápido, mas você não consegue recuperar .class.[/quote]

Eu não sei usar o enum como singleton. Como ficaria o seu uso? Como eu retornaria apenas um objeto com o enum?

[quote=ECO2004][quote=juliocbq]Na minha opinião a melhor maneira de se usar um singleton é essa:

[code]public enum Age {
INSTANCE;
private int age;

public int getAge() {
    return age;
}

}[/code]

Simples e rápido, mas você não consegue recuperar .class.[/quote]

Eu não sei usar o enum como singleton. Como ficaria o seu uso? Como eu retornaria apenas um objeto com o enum?[/quote]

:shock: :shock:

// obtem instancia
Age age = Age.INSTANCE;
// usa a instancia
age.getAge()

Simples.

[quote=sergiotaborda][quote=ECO2004][quote=juliocbq]Na minha opinião a melhor maneira de se usar um singleton é essa:

[code]public enum Age {
INSTANCE;
private int age;

public int getAge() {
    return age;
}

}[/code]

Simples e rápido, mas você não consegue recuperar .class.[/quote]

Eu não sei usar o enum como singleton. Como ficaria o seu uso? Como eu retornaria apenas um objeto com o enum?[/quote]

:shock: :shock:

// obtem instancia
Age age = Age.INSTANCE;
// usa a instancia
age.getAge()

Simples.[/quote]

Está me parecendo que está faltando algo. Pelo que sei de enum, quando invoco uma constante de enum, o seu construtor é chamado. Essa chamada ao construtor é segura. Para mim, falta nesse enum o objeto ao qual se deseja ter apenas uma instância, não é?

[quote=ECO2004][quote=sergiotaborda][quote=ECO2004][quote=juliocbq]Na minha opinião a melhor maneira de se usar um singleton é essa:

[code]public enum Age {
INSTANCE;
private int age;

public int getAge() {
    return age;
}

}[/code]

Simples e rápido, mas você não consegue recuperar .class.[/quote]

Eu não sei usar o enum como singleton. Como ficaria o seu uso? Como eu retornaria apenas um objeto com o enum?[/quote]

:shock: :shock:

// obtem instancia
Age age = Age.INSTANCE;
// usa a instancia
age.getAge()

Simples.[/quote]

Está me parecendo que está faltando algo. Pelo que sei de enum, quando invoco uma constante de enum, o seu construtor é chamado. Essa chamada ao construtor é segura. Para mim, falta nesse enum o objeto ao qual se deseja ter apenas uma instância, não é? [/quote]

Não falta nada. Usa ele diretamente. Como é singleton você não precisa ficar passando suas instâncias em outras referências.

Age.INSTANCE.getAge();

[quote=juliocbq][quote=ECO2004][quote=sergiotaborda][quote=ECO2004][quote=juliocbq]Na minha opinião a melhor maneira de se usar um singleton é essa:

[code]public enum Age {
INSTANCE;
private int age;

public int getAge() {
    return age;
}

}[/code]

Simples e rápido, mas você não consegue recuperar .class.[/quote]

Eu não sei usar o enum como singleton. Como ficaria o seu uso? Como eu retornaria apenas um objeto com o enum?[/quote]

:shock: :shock:

// obtem instancia
Age age = Age.INSTANCE;
// usa a instancia
age.getAge()

Simples.[/quote]

Está me parecendo que está faltando algo. Pelo que sei de enum, quando invoco uma constante de enum, o seu construtor é chamado. Essa chamada ao construtor é segura. Para mim, falta nesse enum o objeto ao qual se deseja ter apenas uma instância, não é? [/quote]

Não falta nada. Usa ele diretamente. Como é singleton você não precisa ficar passando suas instâncias em outras referências.

Age.INSTANCE.getAge();

Com esse seu exemplo, qual é o objeto singleton? Em outras palavras, qual é o objeto que é único na memória?

Sempre que vejo uma implementação de um singleton utilizando o enum acho muiiiitooo extranho… rsrsrs

Sei os motivos de segurança para isso mas, como eu venho de outras linguagens aprendi, que enum é somente um conjunto finito de elementos! Java transformou isso em uma “classe” o que é ótimo pois em outras linguagens, por exemplo, se você queria associar um “Nome” a um valor do enumerador, tinha que fazer uma função só para isso. Mas vendo ele sendo utilizado como singleton é demais :smiley:

Java sempre me surpreende, permite coisas simplesmente incriveis… só perde para C é claro! :smiley: rsrsrsrsr

INSTANCE é unico. Age.INSTANCE é “similar” a chamada um campo publico e estático de uma classe. Note que eu disse similar e não igual, existem coisas sendo feitas nos bastidores!

Você pode entender, nesse caso, que INSTANCE representa a própria classe Age!
O exemplo com enumerador seria parecido com isso, mas usando enum você não tem os problemas já citados de concorrência e segurança!

public class Age {
  
  private Age(){
  }
  
  public static Age INSTANCE = new Age();
  
  public int getAge(){
    return 1
  }
}

[quote=x@ndy][quote=ECO2004]

Age.INSTANCE.getAge();

Com esse seu exemplo, qual é o objeto singleton? Em outras palavras, qual é o objeto que é único na memória?
[/quote]
INSTANCE é unico. Age.INSTANCE é “similar” a chamada um campo publico e estático de uma classe. Note que eu disse similar e não igual, existem coisas sendo feitas nos bastidores!

Você pode entender, nesse caso, que INSTANCE representa a própria classe Age!
O exemplo com enumerador seria parecido com isso, mas usando enum você não tem os problemas já citados de concorrência e segurança!

[code]
public class Age {

private Age(){
}

public static Age INSTANCE = new Age();

public int getAge(){
return 1
}
}
[/code][/quote]

Isso mesmo. INSTANCE aponta pro próprio enum com a vantagem de ser uma chamada estática, o que o torna um ótimo singleton.

[quote=juliocbq]
Isso mesmo. INSTANCE aponta pro próprio enum com a vantagem de ser uma chamada estática, o que o torna um ótimo singleton.[/quote]
Na verdade INSTANCE é INSTANCE! Ele é um elemento do enumerador mas não é o enumerador! Ele também não uma classe, embora tenha comportamento de classe!

O enum pode ser “abstraido” como um conjunto, ou um vetor, com elementos, mas os elementos pertencentes ao conjunto não representam o próprio conjunto.

Por isso acho é muiito esquisito! :smiley:

[quote=juliocbq][quote=x@ndy][quote=ECO2004]

Age.INSTANCE.getAge();

Com esse seu exemplo, qual é o objeto singleton? Em outras palavras, qual é o objeto que é único na memória?
[/quote]
INSTANCE é unico. Age.INSTANCE é “similar” a chamada um campo publico e estático de uma classe. Note que eu disse similar e não igual, existem coisas sendo feitas nos bastidores!

Você pode entender, nesse caso, que INSTANCE representa a própria classe Age!
O exemplo com enumerador seria parecido com isso, mas usando enum você não tem os problemas já citados de concorrência e segurança!

[code]
public class Age {

private Age(){
}

public static Age INSTANCE = new Age();

public int getAge(){
return 1
}
}
[/code][/quote]

Isso mesmo. INSTANCE aponta pro próprio enum com a vantagem de ser uma chamada estática, o que o torna um ótimo singleton.[/quote]

Quer dizer que se eu quiser utilizar o padrão singleton e enum ao mesmo tempo, tenho que transformar a classe o qual desejo ter apenas um objeto em memória em um enum?

Isso que eu não estava entendendo…não estava vendo qualquer referência a uma classe (além de enum).

[quote=x@ndy][quote=juliocbq]
Isso mesmo. INSTANCE aponta pro próprio enum com a vantagem de ser uma chamada estática, o que o torna um ótimo singleton.[/quote]
Na verdade INSTANCE é INSTANCE! Ele é um elemento do enumerador mas não é o enumerador! Ele também não uma classe, embora tenha comportamento de classe!

O enum pode ser “abstraido” como um conjunto, ou um vetor, com elementos, mas os elementos pertencentes ao conjunto não representam o próprio conjunto.

Por isso acho é muiito esquisito! :D[/quote]

Que eu saiba, enum é uma classe com algumas restrições, como ter um construtor que não tem qualquer modificador de acesso, sequer public. Cada constante de um enum é um objeto. A chamada de uma constante chama o construtor desse enum. A chamada de uma constante de enum é seguro para threads.

Este seu conceito está errado. Voc~e realmente precisa conhecer melhor a linguagem antes de se aventurar nos patterns. Senão vai perder muitas nuances.

Quando vc declara um enum, o construtor é chamado pela JVM garantidamente apenas uma vez durante a inicialização da classe ( os campos do enum são automaticamente estáticos e públicos)

É a garantia de ser chaamdo apenas 1 vez mesmo que vc use serialização ou mutliplos classloaders que dá ao enum os poderes necessários para ser um bom singleton. Dito de outra forma, a JVM garante que cada instancia das classes do tipo enum são singletons.
Então, para ter o padrão singleton basta declarar um enum com um único elemento ( e automagicamente ele será um singleton pela estrutura do enum)

Enum não é um padrão em si. Não existe isso de “usar o padrão singleton e o padrão enum ao mesmo tempo”.
Enum é uma forma especial de tipo ( as outras são Classe, Interface e Annotation)

Não ha problema nenhum em uma enumeração só ter um elemento (conjunto singular). Aliás essa é a definição do que significa ser singleton ( único no conjunto)

[quote=ECO2004]
Quer dizer que se eu quiser utilizar o padrão singleton e enum ao mesmo tempo, tenho que transformar a classe o qual desejo ter apenas um objeto em memória em um enum?

Isso que eu não estava entendendo…não estava vendo qualquer referência a uma classe (além de enum). [/quote]Enum não um “Padrão de Projeto”. Basicamente enumeradores são conjuntos finitos de dados. Por exemplo eu posso criar um enum em java para os dias da semana que seria

enum DiasDaSemana { SEGUNDA, TERCA, QUARTA, QUINTA, SEXTA, SABADO, DOMINGO; } Enumeradores são basicamente isso em qualquer linguagem! Você utiliza normalmente na classificação de um tipo de dados, por exempo, se você tem uma classe chamada Dia, poderia utilizar o enum DiasDaSemana para classifica-la.

Porém, em java enumeradores tem comportamento de classe! Você pode definir métodos para eles como no exemplo abaixo:

[code]
enum DiasDaSemana {
SEGUNDA(“Segunda Feira”),
TERCA(“Terça Feira”),
QUARTA(“Quarta Feira”),
QUINTA(“Quinta Feira”),
SEXTA(“Sexta Feira”),
SABADO(“Sabado”),
DOMINGO(“Domingo”);

private String nomeDoDia;

public DiasDaSemana (String nomeDoDia){
this.nomeDoDia = nomeDoDia;
}

public string nomeDoDia (){
return this.nomeDoDia;
}
}
[/code]Quando você cria uma variável para esse enumerador e atribui a ela um dos valores da enumeração a jvm cria para você um único item, que será compartilhado por todas as referencias! Assim você tem sempre um único item da enumeração ‘instanciado’ sempre. Isso faz com que ele seja ótimo para singletons. enums também já foram projetados para serem a prova de threads

PS: Uma coisa que tem que ficar clara é que enumeradores não foram feitos para serem usados como Singletons. Eles são usados por conveniência devido a problemas de segurança e a acesso por theads! Eu, como já comentei, acho estranho até o uso para isso e num mundo ideal com certeza não usaria enumeradores para criar singletons!