The Singleton Pattern
Um singleton é um objeto que não pode ser instanciado.
Em Java precisamos da instância de um objeto para que possamos usa-lo. Bem, um sigleton pode ser criado, mas não é possível instancia-lo. Isso significa que o sigleton terá controle sobre a forma como ele é criado.
Quando usar um Singleton? Quando planejamos um sistema, nós podemos ter a necessidade de controlar como um objeto é usado e prevenir que outros (incluindo nós mesmos) façam cópias ou criem novas instâncias.
Na prática é comum termos objetos que centralizem dados sobre configurações da nossa aplicação. É evidente que um objeto desse tipo não poderá ter mais de uma instância, nem cópias, incluindo até possíveis Threads. É necessário prevenir isso…
Impedindo a criação de instâncias diretas
public class MySingleton{
? ? ? private MySingleton(){
//não é necessário código
}
}
Com isso impedimos que o nosso singleton seja instanciado diretamente, mas precisamos fornecer um método de acesso para a nossa instância controlada do Singleton:
public class MySingleton{
private static MySingleton object;
private MySingleton(){
//não é necessário código
}
public static MySingleton getMySingleton(){
if (object == null)
// não existe instância, podemos chamar este contrutor:
object = new MySingleton();
return object;
}
}
Agora, quando invocado pela primeira vez, o método getMySingleton retornará uma instância do nosso objeto, que permanecerá o mesmo durante a execução do nosso aplicativo.
Prevenindo problemas com múltiplas Threads
Se uma ou mais Threads fizerem a chamada do nosso método uma seguida da outra, corremos o risco de chamar o método getMySingleton duas vezes, e retornando valores diferentes. Prevenir isso é fácil, basta usarmos a keyword synchronized, assim:
public static synchronized MySingleton getMySingleton()
Isso previne que esse problema com as Threads ocorra. Mas será que nosso Singleton está pronto? Suponhamos que a seguinte situação ocorra:
public class Clone{
public static void main(String args[])
throws Exception{
// Pega o Singleton:
MySingleton obj = MySingleton.getMySingleton();
// Vamos clonar o objeto!
MySingleton clone =
(MySingleton) obj.clone();
}
}
O exemplo acima mostra um situação onde nosso Singleton foi furado! Duas instâncias dele foram criadas, usando o método “clone()”. Prevenir isso também é muito simples, nossa versão final do Singleton ficaria assim:
public class MySingleton{
private static MySingleton object;
private MySingleton(){
//não é necessário código
}
public static synchronized MySingleton getMySingleton(){
if (object == null)
// não existe instância, podemos chamar este contrutor:
object = new MySingleton();
return object;
}
public Object clone()
throws CloneNotSupportedException{
throw new CloneNotSupportedException();
}
}
Como podemos ver, um Singleton é um objeto que só pode ser instanciado uma única vez. Criar um objeto desta natureza implica apenas em impossibilitar a criação de várias instâncias.
Oi amigo, gostaria de acrescentar uma prática muito boa para singleton pois manter um metodo syncronizado é muito custoso.
public static MySingleton getMySingleton() {
if (object == null)
synchronized (MySingleton.class) {
if (object == null)
object = new MySingleton();
}
return object;
}
esta pratica se chama dupla checagem pois vc verifica a existencia de uma instancia da Classe em um bloco não sincronizado, posteriormente caso não exista ele entra em um bloco sincronizado para executar a segunda checagem pois podem existir duas requisições de Threads para instanciar a classe. Desta forma vc garante melhor desempenho na sua Classe com singleton pois o bloco sincronizado será executado uma “unica” vez.
Vlw!!!
Att, Sergio Amim Junior.
Sergio,
Agradeço a leitura do artigo e o comentário postado.
Entretanto não posso deixar de observar que essa idéia (”Double checked locking”) é equivocada. Esse é um erro razoavelmente comum, porque parece algo lógico e intuitivo, mas devido ao Java Memory Model, definido no capitulo 17 da JavaLanguage Specification, há um pequeno furo na sua idéia.
Aqui um artigo que explica de forma rápida e clara esse furo:
http://www.javaworld.com/jw-02-2001/jw-0209-double.html
Aqui um outro? mais completo, que? também tem aborda? o assunto:
http://www.javaworld.com/javaworld/jw-02-2001/jw-0209-toolbox.html
Mais uma vez, agradeço o comentário.
[]s
Fabricio Braga
Desculpe, meu senhor, mas a expressão
“Um singleton é um objeto que não pode ser instanciado.”
está um tanto equivocada.
Prezado Sr. Martin Fowler,
Primeiramente gostaria de agradecer a contribuição. Mesmo as críticas são sempre bem vindas aqui neste espaço.
Sobre o ponto observado por você, sou obrigado a discordar, e acredito que o problema aqui é meramente de semântica. Reitero meu postulado: um Singleton é sim, um objeto que não pode ser instanciado!
Se você está conseguindo “fazer alguem instanciar seu Singleton”, sinto muito mas então ele deve ser chamado de outra coisa, não de Singleton. Ocorre que o Singleton é o único responsável pela criação de sua instância, que deve ser única. Conforme dito por mim no artigo, ele não é instanciado (na voz passiva mesmo), mas ele próprio se instancia!
Como eu disse antes, acredito ser apenas um problema de semântica (voz passiva, voz ativa), tenho certeza de concordarmos com o fato de que o Singleton deve ter um única instância.