Criar único objeto com o pattern Singleton

Pessoal, ao testar diversos códigos com o pattern singleton, deparei com um problema, nenhum deles foi 100% eficiente, pelo menos não como
eu desejava que fosse. Aqui vai um código que testei.

[code]class SingletonClass {

private static SingletonClass singletonObject;
/** A private Constructor prevents any other class from instantiating. */
private SingletonClass() {
	//	 Optional Code
}
public static synchronized SingletonClass getSingletonObject() {
	if (singletonObject == null) {
		singletonObject = new SingletonClass();
	}
	return singletonObject;
}
public Object clone() throws CloneNotSupportedException {
	throw new CloneNotSupportedException();
}

}

public class SingletonObjectDemo {

public static void main(String args[]) {
	//		SingletonClass obj = new SingletonClass();

            //Compilation error not allowed
	SingletonClass obj = SingletonClass.getSingletonObject();
	// Your Business Logic
	System.out.println("Singleton object obtained");
}

}[/code]

Se você executar várias vezes, perceberá que o objeto será duplicado… existe alguma possibilidade
de evitar a duplicação do objeto na memória, para criar por exemplo uma única instancia do aplicativo
utilizando o swing…

O código aparentemente está ok. Sempre que eu vi ou fiz Singleton foi assim.

Se executar este código duas vezes, ele vai criar dois objetos pois foram iniciadas duas VMs diferentes (uma para cada execução).
Por isso que na empresa a gente evita Singleton no ambiente JEE. Ninguém garante que o app server vai executar a aplicação sempre na mesma VM (a gente usa Websphere ND, com multiplos servers em um cluster).

O que exatamente está acontecendo?
O que exatamente você está querendo?

Essa é uma péssima implementação de Singleton. Ela é desnecessariamente complexa.

A mais correta no Java é:

[code]class SingletonClass {
private static SingletonClass singletonObject = new SingletonClass();

/** A private Constructor prevents any other class from instantiating. */
private SingletonClass() {
}

public static SingletonClass getSingletonObject() {
	return singletonObject;
}

}[/code]

De qualquer forma, o singleton em java não funciona com multiplos class loaders. Portanto, o Singleton não é um bom padrão para aplicações web no geral (na verdade, não é um bom padrão para aplicações no geral).

Agora, a minha dúvida é. Como você chegou a conclusão que essa classe foi instanciada mais de uma vez?

Eu diria que o mais correto, seria fazer um tipo Enum, para implementar o padrão Singleton.

Essa é uma boa também. Mas acho que ainda mais correto é não usar o padrão Singleton. :smiley:

Seguindo as palavras do Joshua …

[quote=ViniGodoy]

Agora, a minha dúvida é. Como você chegou a conclusão que essa classe foi instanciada mais de uma vez?[/quote]

mandando imprimir …a variavel… ‘singletonObject’, …

Testei vários singletons… e não consegui criar uma única instância de um jframe por exemplo…

Uma das opções foi criar um arquivo ‘lock’ ao iniciar o aplicativo e apagá-lo ao fechar, mas pode ocorrer problemas como o programa ser encerrado
forçosamente, seja por queda de luz por exemplo… ou erro do sistema operacional, ai o arquivo ficaria e ao abrir o aplicativo novamente mostraria
mensagem que já existe instância aberta do aplicativo… e ter que resolver manualmente… isso é o que quero evitar… quem vai usar o aplicativo
não tem se preocupar com isso… quero que o próprio aplicativo resolva…

Espere um pouco. Esse padrão existe no contexto de uma aplicação. Você está tentando criar um Singleton que exista entre múltiplas instância da sua aplicação inteira?

Isso mesmo… não permitir que haja duas instâncias do mesmo aplicativo…, um dos motivos, banco de dados embarcados como mysql, h2, não permitem
que você possua mais de uma instância usando o banco de dados… o padrão singleton funciona no contexto de uma aplicação, mas o caso é diferente…

Então, isso o padrão Singleton jamais se propôs a resolver. Ele garante que exista apenas uma única instancia na aplicação, não entre múltiplas aplicações.

Para fazer o que você quer, existem algumas alternativas:

  1. Usar o lock (como vc já sugeriu, mas tem problemas caso a aplicação aborte);
  2. Abrir um ServerSocket numa porta qualquer. E só manter a aplicação aberta caso consiga;

Mas e a questão da segurança… teria algum problema…

Testei a solução 2 e perfeitamente… ta funcionando melhor que a primeira… quando o aplicativo fecha automaticamente… fecha o ServerSocket…

valew…

Não, nenhum problema. Até pq seu ServerSocket fica mudo, e ignora todos os pacotes que vem através dele.

Eu discordo que singleton é um padrão ruim para aplicações WEB.

Muito pelo contrário em um contexto de injeção de dependências e se tratando da camada de serviços, singleton são bem aceitos. O que não são recomentados são Static Singletons.

Apesar que você pode sim compartilhar uma váriável de instância em uma mesma aplicação web, basta carregar ela em um Classloader anterior.

Exemplo: pasta “/tomcat/common/”

O problema é que existem raríssimas situações onde uma coisa é o que o Singleton se propõe: Única.
E, mesmo as que pensamos que são, geralmente acabam precisando ser duplicadas no futuro.

Então, some ao fato de que uma única instância reduz chances de paralelismo e, se não implementada com muito cuidado, pode quebrar entre múltiplos classloaders, e você vai ter um pattern que acende centenas de alertas, especialmente num servidor web.

Eu gosto do Singleton em sistemas mono-classloader, como muitos sistemas Swing ou jogos (em jogos é ainda melhor, pois há poucas threads).

[quote=ViniGodoy]O problema é que existem raríssimas situações onde uma coisa é o que o Singleton se propõe: Única.
E, mesmo as que pensamos que são, geralmente acabam precisando ser duplicadas no futuro.

Então, some ao fato de que uma única instância reduz chances de paralelismo e, se não implementada com muito cuidado, pode quebrar entre múltiplos classloaders, e você vai ter um pattern que acende centenas de alertas, especialmente num servidor web.

Eu gosto do Singleton em sistemas mono-classloader, como muitos sistemas Swing ou jogos (em jogos é ainda melhor, pois há poucas threads).[/quote]

Concordo com você, que talves devido a complexidade poderiamos optar inicialmente por outras soluções.

[quote=PedroTOliveira]Eu discordo que singleton é um padrão ruim para aplicações WEB.

Muito pelo contrário em um contexto de injeção de dependências e se tratando da camada de serviços, singleton são bem aceitos.[/quote]

Primeira vez que eu vejo alguem dizer isso sem um smilie na frente pra indicar que era piada. Eu vacilei e nao percebi o sarcasmo, ou vc ta mesmo falando serio?

Injecao de dependencias existe EXATAMENTE pra nao ter que ficar com estado global/estatico compartilhado entre instancias. Vai totalmente contra a ideia de que “singletons sao bem aceitos”.

Static Singleton? Porréssa? E o que seria um Dynamic Singleton, diga-se?

[quote=cv][quote=PedroTOliveira]Eu discordo que singleton é um padrão ruim para aplicações WEB.

Muito pelo contrário em um contexto de injeção de dependências e se tratando da camada de serviços, singleton são bem aceitos.[/quote]

Primeira vez que eu vejo alguem dizer isso sem um smilie na frente pra indicar que era piada. Eu vacilei e nao percebi o sarcasmo, ou vc ta mesmo falando serio?

Injecao de dependencias existe EXATAMENTE pra nao ter que ficar com estado global/estatico compartilhado entre instancias. Vai totalmente contra a ideia de que “singletons sao bem aceitos”.

Static Singleton? Porréssa? E o que seria um Dynamic Singleton, diga-se?
[/quote]

Você tem razão, o termo Static Singleton foi infeliz, eu coloquei na cabeça esse termo, por causa da forma como design pattern é aplicado e explicado.
Tem haver com a forma de declarar a instancia da classe de forma static.

Mas também considero que “Singleton” quer dizer:
Garanto que tenho somente uma única instancia dessa classe dentro desse contexto de aplicação.

Tipo:

public class ServicesManager {

    private static final Map services = new HashMap();

    static {
        try {
            services.put("LoginService", Class.forName("com.guj.LoginService").newInstance());
            services.put("RegisterService", Class.forName("com.guj.RegisterService").newInstance());
        } catch (ClassNotFoundException ex) {
            //sei lah
        }
    }

    public static Service getService(String service) {
        if (services.containsKey(service)) {
            return services.get(service);
        } else {
            throw new IllegalArgumentException("Service Not Found");
        }
    }
}

Nesse caso eu não poderia considerar que meu LoginService um Singleton?
Opa, nosso Map também é uma única instancia! (Aqui teriamos um Singleton?).
Não é próximo do que o container de injeção de dependências faz ?
Porquê na documentação do Spring eles se referem aos beans como sendo por “default” configurados como “Singletons”?

Edit: Acho que a tempo ainda.

O papel container de Injeção de Dependências / IOC, para mim, tem mais haver com uma forma de fazer com que certa dependência seja injetada de forma mais “configurável” do que com a eliminação de estado global/estático entre instancias (Por sinal dependendo da implementação/configuração o container não resolve isso).

Outro ponto, é possível injetar dependencias (por default: singletons) de forma dinâmica utilizando recursos AOP e Auto-Wiring do Spring, (Dynamic Singletons?) porém se seus beans possuem atributos compartilhados, você vai ter problemas de classloaders e concorrência do mesmo jeito. (O Container no caso não resolve a questão dos classloaders que o Vini comentou).

Seguindo as palavras do Joshua …[/quote]

Como que se faz isso?