Guia Linguagem Java

Java Generics: Reutilizando seu código

Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Para efetuar o download você precisa estar logado. Clique aqui para efetuar o login
Confirmar voto
0
 (7)  (0)

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.

Listagem 1. Classe Abstrata implementando operações de CRUD

  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.

Listagem 2. PessoaCrudImpl estendendo da classe AbstractCrud

  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.

Listagem 3. Aumentando os recursos de PessoaCrudImpl

  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.

Listagem 4. Alternativa para instanciar objetos com generic

  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.

Veja Também

 
Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Receba nossas novidades
Ficou com alguma dúvida?