Duvida - padrão singleton

pessoal estou com uma dúvida no padrão singleton, eu devo instanciar o objeto estático no atributo ou no método (uma vez comparando se o mesmo é null)

em termos, qual das opcoes é a mais correta, e pq?

esta

private static Objeto objeto = null; public static Objeto getObjeto() { if (objeto == null) objeto = new Objeto(); return objeto; }

ou

private static Objeto objeto = new Objeto(); public static Objeto getObjeto() { return objeto; }

Aí depende da tua necessidade: é preciso invocar o construtor do objeto no momento em que o método for chamado?

a primeira e a correta… pois vc pode ver que a primeira faz o teste para ver se a instancia ja foi criada e se ja foi ele retorna ela senao ele a cria… isto é o singleton retornar uma unica instancia… a 2 sempre instancia o Objeto ou seja retorna n instancias para n chamadas (toda vez q chamar o metodo estatico…)

Certo

Errado.
Ele retorna a mesma instancia.

Mas a primeira realmente está certa, a proposta é que seja lazy loading, ou seja será carregado em memória apenas quando for requisitado.

Até…

Com tudo na vida, não há opções “corretas”, mas opções adequadas para determinado contexto.

O primeiro exemplo é um lazy loading e o segundo é um eager loading. A diferença, óbvio, é que o primeiro pode economizar recurso se o método nunca for chamado. Porém, o primeiro exemplo não é thread-safe, você precisaria implementar o double-checked locking, assim:

class MySingleton {
    private static Objeto objeto = null;
    public static Objeto getObjeto() {
        if (objeto ==  null)
	    synchronized(MySingleton.class) {
	        if (objeto == null) {
		    objeto = new Objeto();
		}
	    }
        return objeto;
    }
}

Porém, muitos argumentam que há um certo exagero ao usar singleton, e que é um meio de se programar proceduralmente, com singleton sendo as variáveis globais (que Java não suporta).

Portanto, tome cuidado.

Tem certeza que a segunda opção instancia um objeto?

[quote=Leonardo3001]
Porém, muitos argumentam que há um certo exagero ao usar singleton, e que é um meio de se programar proceduralmente, com singleton sendo as variáveis globais (que Java não suporta).

Portanto, tome cuidado.[/quote]

Bem observado.
Alguns condenam totalmente o uso de singletons, outros são menos radicais e aderem em casos específicos onde realmente se faz uso do padrão singleton ao invés de um anti-pattern ou algo do gênero.

Leonardo… o double checked locking não é thread-safe e é considerado um anti-pattern. Além disso, gera uma complicação desnecessária no código, para um ganho de performance altamente questionável.

Por favor, leia o material: http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
Ou, com mais detalhes: http://www.ibm.com/developerworks/java/library/j-dcl.html

No geral, é uma má idéia usar singleton. O ideal é usar o padrão registry ou um framework de dependency injection. Eu só recomendo o singleton quando você está rodando uma aplicação que faz uso de um único classloader. Isso exclui praticamente todas as aplicações web. Mas inclui jogos de computadores, aplicações para celular e applets por exemplo.

O singleton também é interessante se você quiser manter sua aplicação simples (não obrigar o seu usuário a ter um framework de DI). Isso é importante se o seu programa precisar ter um binário pequeno (aplicação para celular, palm, applets). Mas nesse caso, procure estudar as desvantagens do singleton e suas limitações.

No caso do singleton com lazy-initialization, a única forma segura de se fazer isso é:

[code]public class Singleton {
private static Singleton myInstance = null;

private Singleton() {}

private static synchronized Singleton getInstance() {
if (myInstance == null)
myInstance = new Singleton();
return myInstance;
}
}[/code]

Geralmente, não é necessária. O Java já tem um esquema de lazy-loading em suas classes. E como a classe do Singleton só é usada se o Singleton for usado, geralmente é preferível manter a classe ultra-simples, com eager loading.

Eu só recomendo em casos de Singletons realmente pesados, que demorem para carregar. Mas esse geralmente não é o caso.

Tudo isso falo assumindo que você vai usar o Singleton para seu propósito: garantir que um objeto terá uma única instância. E não para fazer um “repositório de constantes”.

Eu,

pessoalmente, uso muito pouco o padrão singleton. Mas quando preciso fazer, eu sigo o modelo do último post do Vini, os problemas com a threads são relatados também pelo Joshua no Effective Java, mas existe mais uma opção, em caso da necessidade de executar algum código a mais do new.
Nesse caso, cabe a utilização de blocos static na classe, dessa forma:

public class MinhaClasse { private MinhaClasse mc = null; static { // alguma coisa que precisa ser feita mc = new MinhaClasse(); // outras coisas que precisam ser feitas } ... }

fw

[quote=ViniGodoy]Leonardo… o double checked locking não é thread-safe e é considerado um anti-pattern. Além disso, gera uma complicação desnecessária no código, para um ganho de performance altamente questionável.

Por favor, leia o material: http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
Ou, com mais detalhes: http://www.ibm.com/developerworks/java/library/j-dcl.html

No geral, é uma má idéia usar singleton. O ideal é usar o padrão registry ou um framework de dependency injection. Eu só recomendo o singleton quando você está rodando uma aplicação que faz uso de um único classloader. Isso exclui praticamente todas as aplicações web. Mas inclui jogos de computadores, aplicações para celular e applets por exemplo.

O singleton também é interessante se você quiser manter sua aplicação simples (não obrigar o seu usuário a ter um framework de DI). Isso é importante se o seu programa precisar ter um binário pequeno (aplicação para celular, palm, applets). Mas nesse caso, procure estudar as desvantagens do singleton e suas limitações.

No caso do singleton com lazy-initialization, a única forma segura de se fazer isso é:

[code]public class Singleton {
private Singleton myInstance = null;

private synchronized Singleton getInstance() {
if (myInstance == null)
myInstance = new Singleton();
return myInstance;
}
}[/code]

Geralmente, não é necessária. O Java já tem um esquema de lazy-loading em suas classes. E como a classe do Singleton só é usada se o Singleton for usado, geralmente é preferível manter a classe ultra-simples, com eager loading.

Eu só recomendo em casos de Singletons realmente pesados, que demorem para carregar. Mas esse geralmente não é o caso.

Tudo isso falo assumindo que você vai usar o Singleton para seu propósito: garantir que um objeto terá uma única instância. E não para fazer um “repositório de constantes”. [/quote]

neste caso pq nao precisam ser estáticos ?

Ops, precisam sim. Já corrigi lá em cima.
Foi mal…

Isso é mesmo o ideal. Note que isso implicitamente torna a classe final. Se a classe só tem construtores privados, não é possível extende-la através de herança.

Complementando, convém ter tb um construtor sem argumentos e privado, para evitar que algum desavisado instancie a sua classe com o construtor padrão oferecido pelo java;