Java Generics: Reutilizando seu código
Veja neste artigo como utilizar o poder do Generics em Java para reusabilidade de código, tornando seu projeto mais produtivo e de fácil manutenção.
Este tutorial mostra como utilizar Generics em Java para nos auxiliar na criação de classes robustas e com poder de abstração imenso, ou seja, você será capaz de criar uma classe poderosa o bastante para comportar-se das mais diversas formas possíveis dependendo da situação que você precisar, através do conceito de reusabilidade.
É muito comum em qualquer sistema o uso de operações de CRUD (Inserção, Deleção, Remoção e Pesquisa), mas em certo ponto isso torna um código repetitivo e a produtividade de desenvolvimento do sistema cai muito. Tais problemas poderiam ser solucionados apenas criando uma classe Abstrata com Generics que faça todas as operações considerando o tipo do bean em questão.
Criando uma Classe Crud com Generics
Vamos começar utilizando o poder do Generics com uma classe de CRUD, ou seja, que tenha todas as operações de manutenção a determinado objeto. Nosso objetivo é deixar a nossa classe o mais complexa (em termos de recurso e não de dificuldade) possível para atender as mais diversas possibilidades, sendo assim, apenas em casos muito específicos teremos que criar classes a parte, ou seja, que não estendam nossa classe abstrata. Observe a Listagem 1.
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
/*
* Nossa classe CrudImpl será responsável por todas as operações
* de CRUD do sistema, apenas em alguns casos onde alguma
* operação de CRUD Deverá ser mais especializada que os métodos
* deverão ser sobreescritos (override).
* */
public abstract class AbstractCrud<Bean> {
/*
* Nos permite retornar novas instancias do nosso objeto
*/
protected Bean criadorBean;
protected BasicDAOImpl basicDAO;
public Bean save(Bean bean) {
try {
if (bean == null) {
throw new RuntimeException("O Objeto não pode ser nulo");
}
// Se o seu ID for diferente de NULO quer dizer
// que ele já foi salvo apenas ignoramos um novo "save"
if (bean.getId() != null) {
return bean;
}
return (Bean) getDao().save(bean);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public Bean update(Bean bean) {
try {
if (bean == null) {
throw new RuntimeException("O Objeto não pode ser nulo");
}
// Se o seu ID for NULO, chamamos o save em vez do update
if (bean.getId() == null) {
return save(bean);
}
return (Bean) getDao().update(bean);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public void remove(Bean bean) {
try {
if (bean == null) {
throw new RuntimeException("O Objeto não pode ser nulo");
}
// Se o seu ID for NULO, significa que o objeto não foi salvo,
// então não podemos remove-lo
if (bean.getId() == null) {
throw new RuntimeException(
"Você não pode remover um objeto que ainda não foi salvo");
}
getDao().remove(bean);
} catch (Exception e) {
e.printStackTrace();
}
}
public List<Bean> findAll(Bean bean) {
try {
if (bean == null) {
throw new RuntimeException("O Objeto não pode ser nulo");
}
return (List<Bean>) getDao().findAll(bean);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/*
* Retorna uma instancia do Bean, ou seja, como se estivessemos
* executando o"new MinhaClass();", mas faremos isso com Generics.
*/
public Bean getInstanceOfbean() {
Type type = getClass().getGenericSuperclass();
ParameterizedType paramType = (ParameterizedType) type;
try {
return ((Class<Bean>) paramType.getActualTypeArguments()
[0]).newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
public BasicDAOImpl getDao() {
if (basicDAO == null)
basicDAO = new BasicDAOImpl();
return basicDAO;
}
}
O importante na Listagem 1 é perceber que podemos usar dos mais diversos recursos para tornar nossa classe abstrata e poderosa o suficiente para que adapte-se ao meio, ou seja, dependendo da regra em que estamos trabalhando, nossa classe será capaz de adaptar-se a isto, evitando a reescrita de código.
É verdade que a construção dessa classe pode levar um pouco de tempo e ser demasiadamente trabalhosa, mas vale ressaltar que a criação dessas classes abstratas poderosas, aumentam a produtividade do desenvolvimento de forma escalar, levando ainda em consideração que você pode reutilizar a mesma classe nos mais diversos sistema, ou seja, o trabalho árduo será feito apenas uma vez.
Temos então nossa classe abstrata criada, e pelo fato de ser abstrata, não pode ser implementada. Precisamos então criar uma classe que a implemente.
Para nosso exemplo criaremos a classe PessoaCrudImpl (Listagem 2) que estenderá nossa classe abstrata implementando os métodos necessários e abstraindo todos os recursos contidos na mesma.
public class PessoaCrudImpl extends AbstractCrud<Pessoa> {
}
Nossa classe PessoaCrudImpl tem recurso suficiente para realizar todas as operações de CRUD necessárias, pois através do “AbstractCrud<Pessoa>” dizemos a nossa classe abstrata que o tipo de objeto que estamos trabalhando é do tipo Pessoa e este tipo é atribuído diretamente ao parâmetro “Bean” especificado no “AbstractCrud<Bean>” da nossa classe abstrata.
Veja o quão simples se tornar trabalhar desta forma, evitando trabalho desnecessário. É óbvio que este é um exemplo bem simples do uso de Generics para reusabilidade de código. Você pode usar muito mais recursos do que os mostrados neste artigo, pense na sua lógica de negócio e tente resolver o máximo possível apenas com uma classe Abstrata, assim você evita retrabalho e tem mais tempo para término do projeto.
Podemos, por exemplo, criar uma classe utilizando um recurso muito interessante do Generic que é a criação de uma instância apenas através do seu tipo, como é o caso do nosso método “getInstanceofBean()” que quase que “milagrosamente” cria uma nova instância do nosso objeto apenas conhecendo seu tipo que foi passado pelo “PessoaCrudImpl<Pessoa>”. Na Listagem 3 fazemos uso deste método aplicando uma lógica de negócio própria, apenas para você entender que poderíamos aplicar diversas funcionalidades para este método.
public class PessoaCrudImpl extends AbstractCrud<Pessoa> {
public Pessoa prepararInsercaoDePessoa(){
Pessoa pessoa = getInstanceOfbean();
pessoa.setPessoaFisica(new PessoaFisica());
pessoa.setContato(new Contato());
pessoa.setNumerador(criarNumeracaoDePessoa());
if (pessoa.getNumerador > 100){
pessoa.setNivel(pessoa.getNumerador() / 5);
}
return pessoa;
}
}
Veja na Listagem 4 uma alternativa a instanciação de objetos usando generics.
package org.foo.com;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* Basically the same answer as noah's.
*/
public class Home<E>
{
@SuppressWarnings ("unchecked")
public Class<E> getTypeParameterClass()
{
Type type = getClass().getGenericSuperclass();
ParameterizedType paramType = (ParameterizedType) type;
return (Class<E>) paramType.getActualTypeArguments()[0];
}
private static class StringHome extends Home<String>
{
}
private static class StringBuilderHome extends Home<StringBuilder>
{
}
private static class StringBufferHome extends Home<StringBuffer>
{
}
/**
* This prints "String", "StringBuilder" and "StringBuffer"
*/
public static void main(String[] args)
throws InstantiationException, IllegalAccessException
{
Object object0 = new
StringHome().getTypeParameterClass().newInstance();
Object object1 = new
StringBuilderHome().getTypeParameterClass().newInstance();
Object object2 = new
StringBufferHome().getTypeParameterClass().newInstance();
System.out.println(object0.getClass().getSimpleName());
System.out.println(object1.getClass().getSimpleName());
System.out.println(object2.getClass().getSimpleName());
}
}
No exemplo da Listagem 4 não retornamos o objeto instanciado mas sim uma classe para então podermos instanciar o objeto em outro local, no nosso caso, utilizamos o método “main” para tal tarefa. Criamos três objetos distintos apenas com o uso de Generics.
Com isso, podemos concluir que o uso do Generics sem dúvida é um assunto vasto e muito poderoso. O objetivo deste artigo foi mostrar o uso de tal recurso aplicado a reusabilidade de código, dando foco a instanciação de objetos utilizando Generics.
- Curso de Java Orientado a Objetos Básico
- ">Curso de Java Web: Servlet, JSP, JSTL e Tags
Artigos relacionados
-
Artigo
-
Artigo
-
Artigo
-
Artigo
-
Vídeo