Olá Pessoal, tudo bom?
Esse artigo inicia uma série de novos artigos que estão relacionados a padrões de codificação ou Design Patterns. Mais especificamente esse artigo irá retratar o padrão Singleton e como ele é aplicado em códigos Java.
Reinventando a Roda…
Durante o desenvolvimento de aplicações e sistemas, existem muitos problemas que aparecem repetidas vezes em vários momentos de um projeto. Esses problemas podem ser da ordem de correção de erros e defeitos ou para refatoramento de código visando uma melhor performance.
Dessa forma para um mesmo problema podem existir inúmeras soluções, o que poderia causar uma perda de padrão de projeto ou ainda códigos idênticos em diferentes áreas de uma aplicação. Assim para que não ocorram perda de tempo ou recursos, é necessária uma boa avaliação dos desenvolvedores a fim de escolher uma solução consolidada para a resolução de um problema.
Para diversos problemas essa solução consolidada acabou se tornando como um “Santo Grall”, quem achava soluções muitas vezes mantinha-as em seus cubículos, não compartilhando com o mundo. Em 1995, os autores Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides reuniram os padrões de desenvolvimento mais consolidados naquele momento e compilaram em um livro de nome “Design Patterns: Elements of Reusable Object-Oriented Software” da editora Addison-Wesley ((https://books.google.com.br/books?id=6oHuKQe3TjQC&redir_esc=y – Livro Design Patterns: Elements of Reusable Object-Oriented Software” da editora Addison-Wesley)). Esses autores passaram a ser conhecidos como “Gang of Four ou GoF”, tornando-se autores seminais na área de desenvolvimento de software.
Com esse livro surge também o conceito de padrão de projetos ou design pattern:
“Solução consolidada para um problema recorrente no desenvolvimento e manutenção do software”
Assim as vantagens de utilizar os padrões de projeto são as seguintes:
- Evitar a redescoberta de soluções, propiciando o uso de soluções corretas
- Melhorar a qualidade e confiabilidade do software
- Promover um padrão comum de desenvolvimento
- Reduzir o volume de documentação
- Economizar recursos de desenvolvimento
- Conduzir ao bom uso da orientação a objetos
Padrão Singleton
A instanciação de objetos dentro de um projeto de software pode ser uma tarefa extremamente complexa, assim existem alguns padrões citados pelo GoF que são responsáveis pela tarefa de criação de objetos. Um dos problemas encontrados é a criação de várias instâncias de uma classe onde apenas uma instância poderia suprir a necessidade do projeto. Esse padrão de garantir a criação e a existência de uma única instância de uma classe, fornecendo um meio de recuperar essa instância é chamado de Singleton.
Um dos problemas que o padrão Singleton corrige é a falta de controle sobre a criação de objetos. Além desse problema outros problemas relacionados estão na falta de controle sobre a passagem de parâmetros para os objetos, juntamente com o excesso da passagem desses parâmetros.
Dessa forma ao utilizar o padrão é possível assegurar que existe apenas uma instância da classe em toda a aplicação na JVM, sendo que esta instância é acessível para qualquer classe, garantindo que todas utilizem a mesma instância singleton da classe.
Criando a classe Singleton
Para criar uma classe Singleton é necessário realizar os seguintes passos:
- Criar um atributo estático do mesmo tipo da classe com o nome instance
- Todos os construtores da classe devem utilizar o modificador private
- Criar um método estático getInstance() que retorna o atributo instance
Assim todos esses passos estão resumidos na seguinte classe da Figura 01.
E o código desta classe é representado abaixo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public class SingletonExemplo { //Atributo do mesmo tipo da classe private static SingletonExemplo instance; //Construtores privados private SingletonExemplo(){ /*Inicializacoes*/ } //Metodo getInstance() estático public static SingletonExemplo getInstance(){ if(instance == null){ instance = new SingletonExemplo(); } return instance; } } |
É possível melhorar um pouco mais esse exemplo, pois note que dentro do método getInstance() é utilizado um IF para verificar se o objeto instance já foi criado. É possível realizar essa instanciação diretamente no atributo instance, evitando assim a criação do IF dentro do método getInstance(), como podemos verificar no código abaixo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public class SingletonExemplo { //Atributo do mesmo tipo da classe private static SingletonExemplo instance = new SingletonExemplo(); //Construtores privados private SingletonExemplo(){ /*Inicializacoes*/ } //Metodo getInstance() estático public static SingletonExemplo getInstance(){ return instance; } } |
Agora é necessário verificar como será a utilização desta classe.
Utilização da classe Singleton
Para utilizar a classe é necessário apenas chamar o método getInstance(), como podemos verificar no exemplo:
1 2 3 4 5 6 7 8 9 10 11 |
import org.junit.Assert; import org.junit.Test; public classe SingletonExemploTeste{ @Test public void criar() { SingletonExemplo se = SingletonExemplo.getInstance(); Assert.assertNotNull(se); } } |
Esse teste foi construído para rodar na ferramenta JUnit. Caso não conheça a ferramenta há um tutorial aqui.
Se o teste ficou verde significa que a classe está obtendo a instância de SingletonExemplo de forma correta.
Aplicações no Mundo Real
Como é possível perceber é possível que um projeto não utilize singletons. Primeiro porque é uma forma de caracterizar “variáveis globais”, qualquer um pode acessar a instância dessa classe e utilizá-la.
Mas mesmo assim é possível ter aplicações no mundo real. Por exemplo, você gostaria de estabelecer um padrão único de log de ações de usuários, pode utilizar uma singleton para isso, pois você pode criar uma classe que receba uma instância do usuário e realize ações de log.
Outro caso é quando você tem um projeto pequeno e não gostaria de complicar muito as coisas, por exemplo não utilizar CDI (Context Dependency Injection ou Injeção de Dependencias), para injetar classes das camadas de Business Controller ou da camada DAO. Dessa forma podemos utilizar singletons para mantermos a baixa criação de instâncias dessas camadas.
finally{
Esse código que representa um singleton é um código básico, não implementa sincronia de threads ou outras formas mais avançadas de implentação. Isso será visto em um próximo artigo sobre Singletons avançados.
Duvidas ou sugestões? Deixe seu feedback! Isso ajuda a saber a sua opinião sobre os artigos e melhorá-los para o futuro! Isso é muito importante!
Até um próximo post!
Marco Brainciac says
Muito bom ajudou bem na compreensão
Valeu
Mauda says
Olá Marco, tudo bom?
Obrigado pelo feedback!
Continue visitando o site quando puder e precisando estamos aqui!
Obrigado