Em programação orientada a objetos, uma classe singleton é uma classe que pode haver somente um objeto (uma instância da classe) por vez.
Após a primeira vez, se tentarmos instanciar a classe Janela
, a nova variável irá apontar para a primeira instância criada. Portanto, quaisquer modificações que façamos em qualquer variável dentro da classe através de qualquer instância, ela afeta a variável da instância única criada e fica visível se acessarmos essa variável através de qualquer variável do tipo de classe definida.
Para criar uma classe singleton é necessário:
- Mudar a visibilidade do construtor para privado;
- Escreva um método estático que retorne um objeto do tipo da classe singleton.
Classe normal x classe Singleton: A diferença em termos de instanciação é que, para a classe normal, usamos construtor, enquanto que para a classe singleton, usamos um método estático que retorna uma instancia (método getInstance()
). Em geral, para evitar confusão, também podemos usar o nome da classe como nome do método ao definir esse método
Implementação da classe Singleton com o método getInstance()
// Programa Java implementando uma classe Janela
// com o método getInstance()
class Janela
{
// variavel estatica do tipo Janela
private static Janela singleInstance = null;
// variavel do tipo String
public String s;
// construtor privado
private Janela()
{
s = "Ola, sou uma string"
}
// metodo estatico para criar
// a instancia da classe Janela
public static Janela getInstance()
{
if (singleInstance == null) {
singleInstance = new Janela();
}
return singleInstance;
}
}
// Classe principal
class Main
{
public static void main(String args[])
{
// declarando a variavel x e atribuindo uma instancia de Janela
Janela x = Janela.getInstance();
// declarando a variavel y e atribuindo uma instancia de Janela
Janela y = Janela.getInstance();
// declarando a variavel z e atribuindo uma instancia de Janela
Janela z = Janela.getInstance();
// alterando a string
x.s = (x.s).toUpperCase();
System.out.println("String x:" + x.s);
System.out.println("String y:" + y.s);
System.out.println("String z:" + z.s);
System.out.println("\n");
// alterando a string
z.s = (z.s).toLowerCase();
System.out.println("String x:" + x.s);
System.out.println("String y:" + y.s);
System.out.println("String z:" + z.s);
}
}
Saída:
String x:OLA, SOU UMA STRING
String y:OLA, SOU UMA STRING
String z:OLA, SOU UMA STRING
String x:Ola, sou uma string
String y:Ola, sou uma string
String z:Ola, sou uma string
Explicação: Na classe Janela, quando o método getInstance()
é invocado pela primeira vez, ele cria um objeto da própria classe e atribui para a variável singleInstance
, que finalmente o valor é retornado. Como singleInstance é estático, ele é alterado de nulo para algum objeto. Da próxima vez, se tentarmos chamar o método getInstance()
, como singleInstance não é nulo, ele será retornado, em vez de instanciar a classe Janela novamente. Esta parte é feita pela estrutura condicional if
.
Na classe principal, declaramos 3 variáveis (x
, y
e z
) e atribuimos o retorno do getInstance()
a essas variáveis. Na primeira chamada de getInstance()
uma instancia de Janela é criada (variável x
). Nas duas chamadas seguintes de getInstance
(criação das variáveis y
e z
) a mesma instancia de Janela é retornada, não sendo possível a criação de novos objetos.
Temos então 3 variáveis (x
, y
e z
) que fazem referência a um mesmo objeto. Portanto, se alterarmos as variáveis do objeto x
, isso será refletido nas variáveis y
e z
. Além disso, se alterarmos valores na variável z
, isso será refletido quando acessarmos as variáveis dos objetos x
e y
.