Pesquisar este blog

quinta-feira, 9 de fevereiro de 2012

Java: Polimorfismo e Retorno Covariante

Hoje iremos abordar um assunto novo na plataforma Java, que é o retorno covariante. O retorno covariante é uma nova funcionalidade adicionada na plataforma Java a partir da versão 5 que permite utilizar a hierarquia das classes no retorno de métodos, quem pretende realizar o exame de certificação SCJP deve estudar bem os tipos de retorno covariante, pois é cobrado no exame.

Polimorfismo
Antes de entrar direto em retorno covariante vale à pena dar uma olhada no conceito de polimorfismo. O polimorfismo é um conceito de orientação a objetos que permite ver um objeto de várias formas.

Para exemplificar o conceito de polimorfismo vamos analisar a hierarquia de classes abaixo:

http://www.oficinadanet.com.br//imagens/coluna/2531//imagem_1.jpg

Nesse modelo temos as seguintes classes: Pessoa, PessoaJuridica, Cliente e Funcionario, seguindo esta hierarquia temos as seguintes situações polimórficas:
  1. Um cliente é uma pessoa jurídica e também é uma pessoa;
  2. Um funcionário é uma pessoa física e também é uma pessoa;
  3. Um funcionário não é uma pessoa jurídica;
  4. Um cliente não é uma pessoa física.


Polimorfismo pode ser usado em diferentes situações na criação de objetos, nos parâmetros de método e etc.

Seguindo o conceito de polimorfismo podemos ter a seguinte situação:
//crinado uma instância da classe cliente
Cliente cliente = new Cliente();

//vendo a instância de cliente como pj
PessoaJuridica pJuridica = cliente;

//vendo cliente como pj, e a pj como pessoa
Pessoa pessoa = pJuridica;

Uma boa dica para aprender polimorfismo é estudar a API de I/O do java, esta API utiliza e muito os recursos de polimorfismo, e a maioria dos métodos da API utilizam dos recursos de polimorfismo, com a finalidade de deixar o código genérico para trabalhar com os diferentes tipos de implementação.

A grande vantagem de usar polimorfismo é que podemos deixar nosso código flexível a uma mudança e de fácil entendimento.

Entendendo o Casting
A operação de casting é muito comum na programação orientada a objetos, para entender polimorfismo e retorno covariante é fundamental ter um bom conhecimento dessa operação. Existe o casting de tipos primitivos e casting de objetos, vamos focar em casting de objetos, com objetos temos dois tipos de casting, que são o up e o down.

O cast up é uma operação que acontece sem a necessidade de forçar a mudança de tipo, por exemplo, uma instância de Cliente pode ser vista como uma PessoaJuridica, uma Pessoa e até mesmo como Object. O cast down é um cast que deve ser explicito, isso acontece porque o compilador não pode garantir a integridade da instância.

Agora vamos analisar os casting:
//1
Cliente cliente = new Cliente();

//2
PessoaJuridica pJuridica = cliente;

//3
Pessoa pessoa = pJuridica;

//4
Cliente cliente2 = (Cliente)pessoa;

  1. Criação de um objeto do tipo Cliente;
  2. Cast Up, não há necessidade de forçar a mudança de tipo, pois Cliente é uma PessoaJuridica;
  3. Cast Up, PessoaJuridica é uma Pessoa;
  4. Cast Down, necessário para garantir a integridade da instância, pois o compilador não consegue saber se realmente se trata do tipo especificado, porque a instância é criada em tempo de execução, e em caso dos tipos serem incompatíveis é lançada uma exceção do tipo runtime, chamada de ClassCastException.

Retorno Covariante
Agora voltando ao assunto principal da matéria, antes da funcionalidade de retorno covariante tínhamos que trabalhar sempre com as classes mais genéricas nos retornos dos métodos para termos uma flexibilidade maior no código, com isso, sempre precisávamos utilizar da técnica de cast down para poder manipular os retornos dos métodos.

Análise o seguinte exemplo, onde temos uma classe DAO para a entidade Cliente e temos uma interface com o método necessário para manipular os recursos do banco de dados:

Interface BaseDAO:
package classes;
public interface BaseDAO
{
    public Pessoa consulta();
}

Classe ClienteDAO
package classes;
public class ClienteDAO implements BaseDAO
{
    public Pessoa consulta()
    {
        return null;
    }
}

Com o cenário acima temos uma solução para trabalhar com interfaces e banco de dados, mas não a melhor, se você analisar a classe ClienteDAO ela tem a finalidade de trabalhar com a entidade Cliente, então o método consulta() deve retornar um Cliente do banco de dados, mas ele esta retornando uma Pessoa, com isso será necessário realizar a operação de cast down para ver o resultado como um Cliente.

É necessário realizar um cast down desse tipo:
ClienteDAO cliDAO = new ClienteDAO();

Cliente cliente = (Cliente)cliDAO.consulta();

O cast down é necessário porque o compilador não pode garantir a integridade da instância, isso acontece porque você esta querendo ver um tipo Pessoa como Cliente. Com o retorno covariante podemos evitar o cast down e deixar nossa classe ClienteDAO totalmente direcionada a entidade Cliente. O retorno covariante permite que ao sobrescrever um método de uma classe ou interface, o valor de retorno possa ser o mesmo ou um subtipo do retorno. 

Com retorno covariante nosso cenário da classe ClienteDAO ficaria dessa forma:
package classes;
public class ClienteDAO implements BaseDAO
{
    public Cliente consulta()
    {
        return null;
    }
}


Agora nosso método consulta () já retorna o Cliente, assim podemos deixar nosso código mais flexível e fácil de programar novas funcionalidades. Na chamada do método não é mais necessário realizar o cast down porque o nosso método já retorna o Cliente:
ClienteDAO cliDAO = new ClienteDAO();

Cliente cliente = cliDAO.consulta();

Retorno covariante é uma funcionalidade muito importante adicionado a partir do Java 5 e também é um conteúdo cobrado na certificação SCJP, então quem pretende realizar o exame deve ter esses conceitos bem em mente.


Nenhum comentário:

Postar um comentário