Olá Pessoal, tudo bom?
Esse artigo é a continuação de uma série de artigos que estão relacionados a padrões de codificação ou Design Patterns. Mais especificamente esse artigo irá retratar o padrão Factory e como ele é aplicado em códigos Java.
Classes Literais e Concretas
Um padrão comum, até mesmo por questões de portabilidade em códigos Java é utilizar literais, ou seja, classes abstratas ou interfaces, para criação de atributos ou parâmetros de métodos. Isso é muito comum ao trabalhar com a biblioteca Collection do Java. Normalmente é criado um atributo do tipo List<?> e não um ArrayList<?> diretamente. Isso se deve ao fato de podermos, via Polimorfismo, passar qualquer instância de classe que em sua Hierarquia seja um List<?>. O código abaixo representa um método de ordenação de palavras cujo parâmetro é uma List<String>.
1 2 3 4 5 6 7 8 9 10 11 12 |
//Utiliza bubble sort, mas ok eh só um exemplo :-) public void ordenaPalavras(List<String> palavras){ for(int i = 0; i < palavras.size(); i++){ for(int j = i+1; j < palavras.size(); j++){ if(palavras.get(i).compareTo(palavras.get(j)) > 0){ String swap = palavras.get(i); palavras.set(i, palavras.get(j)); palavras.set(j, swap); } } } } |
E aqui temos uma chamada de teste para esse método:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import java.util.ArrayList; import java.util.List; import org.junit.Test; public classe OrdenacaoExemploTeste{ @Test public void testeOrdenacao() { List<String> array = new ArrayList<String>(); array.add("Teste"); array.add("Abacaxi"); array.add("Despites"); ordenaPalavras(array); for (String string : array) { System.out.println(string); } } } |
Esse teste foi construído para rodar na ferramenta JUnit. Caso não conheça a ferramenta há um tutorial aqui.
Repare na linha 09, ao invés de realizar um new em um List<String>, que é impossível já que List é uma interface, foi realizada uma instanciação de ArrayList. Caso fosse mudado o exemplo para LinkedList, iria funcionar também. O que acontece aqui é que uma classe Literal, necessariamente precisa de uma classe concreta.
Isso é muito importante quando temos uma hierarquia de classes considerável, por exemplo, uma classe Literal Ambiente, mas várias filhas, Casa Show, Cinema e Teatro. Dessa forma ao invés de termos métodos que recebem uma filha, por exemplo Cinema, é possível optar por receber uma classe pai, Ambiente. Podendo dessa forma reutilizar vários métodos. Isso é chamado de Princípio de Programação por Interface.
Esse princípio também pode ser aplicado para a criação dos objetos da hierarquia, utilizando o padrão Factory, assim se tivermos os seguintes itens:
- Classes pai e filhas organizadas em uma hierarquia de herança ou implementação de interface.
- Algumas maneiras de criar uma instância de uma classe filha.
- Não existir a necessidade de conhecimento de como é a criação de uma classe filha.
Pattern Factory
A definição do padrão Factory, de acordo com o Livro de Design Patterns ((https://books.google.com.br/books?id=6oHuKQe3TjQC&redir_esc=y)) é o seguinte:
Padrão que define uma interface* para criar um objeto, mas permite às classes decidirem qual classe instanciar. Permite a uma classe deferir a instanciação para subclasses
*Essa interface não é uma interface Java, mas sim uma forma de criar um objeto, no nosso caso será uma classe Java.
Esse padrão é amplamente utilizado na produção de software, sendo baseado no padrão do Encapsulamento. Esse padrão também possui a característica de centralizar a criação de objetos dentro da hierarquia, tornando mais fácil manutenções sobre a criação de objetos e a inserção da criação de novos tipos de objetos, provendo um baixo acoplamento e alta coesão.
Assim o diagrama de classes que configura esse padrão está descrito na Figura 01:
A fim de facilitar a explicação, tomei a liberdade de criar um Enum que contém todos os tipos da hierarquia T. Esse enum é passado para o método getInstance(TypeT) da classe FactoryT, o qual através desse tipo irá retornar uma instância do tipo correspondente.
Difícil compreender utilizando esse diagrama? Sim o diagrama torna um pouco mais complicado o entendimento, por isso vamos fazer um exemplo, conforme mostra a Figura 02:
É possível perceber que foi criado um Enum, de nome TipoBilhete, o qual contém valores do tipo Economica, Executiva e Primeira. Uma instância de um desses tipos é passado para o método getInstance(TipoBilhete) da classe BilheteFactory, o qual retorna uma instância de Economica, Executiva ou Primeira de acordo com o tipo. O restante da hierarquia é igual a qualquer outra hierarquia de classes Java, onde não nos alongaremos na explanação destas.
Agora vamos verificar como seria criada a classe BilheteFactory
Criando a classe BilheteFactory
Para criar uma classe Factory é necessário realizar os seguintes passos:
- Criar um método, se possível estático, que retorne todas as instâncias de uma hierarquia.
- Para facilitar a criação utilize um switch case para o enum.
Assim o código desta classe é representado abaixo:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class BilheteFactory { public static Bilhete getInstance(TipoBilhete enum){ switch (enum) { case ECONOMICA: return new Economica(); case EXECUTIVA: return new Executiva(); case PRIMEIRA: return new Primeira(); } return null; } } |
Agora é necessário verificar como será a utilização desta classe.
Utilização da classe Factory
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 12 |
import org.junit.Assert; import org.junit.Test; public classe FactoryExemploTeste{ @Test public void criar() { Bilhete bilhete = BilheteFactory.getInstance(TipoBilhete.ECONOMICA); Assert.assertNotNull(bilhete); Assert.assertTrue(TipoBilhete.ECONOMICA.equals(bilhete.getTipo())); } } |
Se o teste ficou verde significa que a classe está obtendo a instância da filha de Bilhete de forma correta.
Aplicações no Mundo Real
A utilização básica está justamente no fato de criar fábricas de classes para utilizarmos conforme a necessidade de nossos sistemas. Não há muito o que comentar, pois o próximo exemplo já explicitou a principal forma de utilização deste padrão.
finally{
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!
Leave a Reply