Buscar

Aula 07 - LPG

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você viu 3, do total de 7 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você viu 6, do total de 7 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Prévia do material em texto

Aula 07: POLIMORFISMO Continuação 
 
Objetivos 
 
 
 Recordando... 
Em aulas passadas, empregando o conceito de herança, criamos uma superclasse abstrata 
Empregado, da qual derivavam três subclasses EmpComissionado, EmpAssalariado e 
EmpHorista. Vimos como declarar um objeto como sendo estaticamente de uma 
superclasse, mas instanciá-lo dinamicamente de uma subclasse. Hoje vamos criar uma 
array de objetos distintos usando a técnica de herança e tratar seus métodos de forma 
polimórfica. 
 Declarando um array de empregados 
Vejamos, primeiramente, a declaração para criar um array de quatro empregados (veja 
que foi usada a superclasse abstrata Empregado): 
 Empregado empregados[] = new Empregado[4]; 
Entretanto, a superclasse é abstrata e cada instanciação de objeto tem que ser de uma das 
subclasses não abstratas, como no exemplo abaixo: 
 
 empregados[2] = new EmpAssalariado ("Joaquim", "Alberto","192837465-99", 1000); 
 
Para fazermos referência ao método salário, que foi sobreposto em cada uma das 
subclasses, podemos usar o polimorfismo de método: 
 
 empregados[i].salario(); 
 
Entretanto, quando formos fazer referência a um método da classe derivada que além de 
ter sido sobreposto (reescrito na subclasse) foi também sobrecarregado (foram criadas 
diferentes versões na subclasse passando diferentes quantidades de parâmetros), será 
necessária uma referência explicita à subclasse, para que o compilador possa fazer a 
resolução da referência estática. Faremos isso através de um mecanismo chamado 
coerção explícita (casting). Com este mecanismo, é possível criar um objeto da 
subclasse e atribuir a ele a referência a um objeto da superclasse que tenha sido 
anteriormente criado. Desta forma, o compilador consegue compreender uma referência 
a um método que tenha sido sobrecarregado na subclasse. 
 Fazendo uma coerção explícita 
O Java permite a atribuição de uma referência de superclasse a uma variável de subclasse 
por meio de uma coerção (cast) explícita, técnica conhecida como downcasting. 
Vejamos como realizar o downcasting: 
EmpAssalariado empAssalariado = (EmpAssalariado) empregados[j]; 
 Reforçar o conceito de polimorfismo de método 
 Criar arrays de objetos 
 Trabalhar com vinculação dinâmica 
 Aprender a utilizar polimorfismo de interface 
 
 
Isto foi necessário, pois desejamos poder chamar tanto o método salário(), sem 
parâmetros e que não exige casting, quanto o método salário(double abono), que foi 
sobrecarregado (e, portanto, não existe na superclasse). 
 
 A implementação do array e do casting 
Para realizar as implementações desejadas, só necessitamos mudar a classe 
EmpAssalariado (para que o método toString não mais chame o método salario com 
parâmetro de abono) e a classe de teste Principal. 
public class Principal{ 
 public static void main ( String argv[]) { 
 Empregado empregados[] = new Empregado[4];// array 
 empregados[0] = new EmpFixoComissionado ("Carlos", 
 "Silva","123456789-10", 10000, 0.02, 300, 0.01); 
 empregados[1] = new EmpComissionado ("Francisco", 
 "Matos","987654321-00", 20000, 0.02, 0.01); 
 empregados[2] = new EmpAssalariado ("Joaquim", 
 "Alberto", "192837465-99", 1000); 
 empregados[3] = new EmpHorista ("Felipe", 
 "Martins", "999888765-43", 100); 
 for ( int j = 0; j < empregados.length; j++ ){ 
 System.out.printf( "Empregado da classe %s \n", 
 empregados[j].getClass().getName()); 
 System.out.println (empregados[j]); // toString 
 if ( empregados[j] instanceof EmpAssalariado ) { 
 EmpAssalariado empregadoA = (EmpAssalariado) 
 empregados[j]; 
 System.out.printf( 
 "Salario (com abono): R$ %.2f\n\n", 
 empregadoA.salario(200)); 
 } // fim do if 
 } // fim do for 
 } // fim do método main 
} // fim da classe Principal 
Na classe EmpAssalariado, só muda o método toString: 
 public String toString () { 
 return String.format ( 
 "%s%s %s\n%s%s\n%s%.2f", 
 "Identificacao: ", nome, sobrenome, 
 "CPF: ", cpf, "Salario Total: ", salario()); 
 } 
 
A classe EmpHorista já foi acrescentada no desafio da aula passada: 
//Classe Empregado Horista 
public class EmpHorista extends Empregado { 
 private final double valorHora = 7.50; 
 protected double horasTrabalhadas; 
 // Construtor com 4 argumentos 
 public EmpHorista (String nome, String sobrenome, 
 String cpf, double horasTrabalhadas){ 
 super (nome, sobrenome, cpf); 
 setHorasTrabalhadas(horasTrabalhadas); 
 } 
 public void setHorasTrabalhadas (double 
 horasTrabalhadas){ 
 this.horasTrabalhadas = horasTrabalhadas; 
 } 
 public double getHorasTrabalhadas(){ 
 return horasTrabalhadas; 
 } 
 public double salario(){ // Calcula salário simples 
 return (getHorasTrabalhadas()*valorHora); 
 } 
 public String toString () { 
 return String.format ("%s%s %s\n%s%s\n%s%.2f\n", 
 "Identificacao: ", nome, sobrenome, 
 "CPF: ", cpf, "Salario total: ", salario()); 
 } 
} // fim da classe Empregado Horista 
 As demais classes são iguais às da aula passada. Compile e teste. 
 Alterando o for 
Além da implementação utilizando o comando for “clássico” como visto acima, 
podemos alternativamente empregar o comando for estendido, disponível a partir do 
Java 5. Com ele, a implementação da classe Principal fica mais “elegante”, dispensando 
o uso de uma variável de controle e aproveitando a dimensão da declaração do tipo 
array. Veja: 
 for ( Empregado empregadoAtual : empregados ){ 
 System.out.printf( "Empregado da classe %s \n", 
 empregadoAtual.getClass().getName()); 
 System.out.println (empregadoAtual); 
 if (empregadoAtual instanceof EmpAssalariado ) { 
 EmpAssalariado empregadoA = (EmpAssalariado) empregadoAtual; 
 System.out.printf("Salario (com abono): R$ %.2f\n\n", 
 empregadoA.salario(200)); 
 } // fim do if 
 } // fim do for 
Faça a alteração, compile e teste desta outra forma. 
 
 
 Usando interfaces 
Ainda no exemplo da aula passada, o que fizemos foi criar uma superclasse destinada 
apenas a definir o que é comum às subclasses dela derivadas, sem que se tenha a 
intenção de efetivamente instanciar objetos dessa classe, que é conhecida como classe 
abstrata. 
Outra forma de conseguir esse resultado é criando uma Interface. Uma interface define 
um conjunto de métodos que uma classe deve implementar, mas não define como esses 
métodos devem ser implementados. É utilizada quando classes não relacionadas 
necessitam compartilhar métodos e constantes. Isto permite que instâncias de classes não 
relacionadas sejam processadas de forma polimórfica, ou seja, respondam às mesmas 
chamadas de métodos. 
O programador pode criar uma interface que descreva a funcionalidade desejada e então 
implementar essa interface em quaisquer classes que requeiram essa funcionalidade. 
Utiliza-se uma interface no lugar de uma classe abstrata quando não há nenhuma 
implementação padrão a herdar – nenhum atributo (variável de classe) e nenhum método 
com implementação. Uma interface é, essencialmente, uma coleção de constantes e 
métodos abstratos. Métodos em uma interface são sempre públicos e abstratos. 
Constantes em uma interface são sempre públicas, estáticas e final. 
A interface resolve o problema de Java não suportar herança múltipla como outras 
linguagens (C++,por exemplo), de forma mais elegante, pois apenas relaciona as 
funcionalidades necessárias às classes. 
No nosso exemplo, se encararmos o salário a ser pago a um empregado como uma 
despesa, podemos observar que outras classes não relacionadas a empregados podem 
também representar despesas. 
Por exemplo, uma fatura é uma despesa e poderíamos criar uma interface Pagamento, 
que fosse comum às faturas e aos 
empregados, na qual houvesse um 
método para calcular o pagamento. 
Embora aplicado a coisas não 
relacionadas (faturas e empregados), o 
método tem a ver com obter algum valor 
a ser pago. 
A modelagem do sistema teria agora o 
aspecto da figura ao lado. 
Como já vimos, em Java as classes só 
podem ter uma superclasse pois Java não 
suporta herança múltipla. Em 
contraposição, uma classe pode 
implementar várias interfaces além de 
herdar de uma classe. Exemplo: 
 public class Testa implements Interface1, Interface2, interface3 extends 
SuperClasse 
 
 Revendo a aplicação 
Para consolidar os conceitos de arrays de objetos, casting de classes e criação de 
interfaces, vamos alterar a aplicação que fizemos na aula passada para o código que se 
segue. 
A interface Pagamento possui uma sintaxe que apenas declara os métodos que serão 
implementados pelas classes que implementem esta interface. No nosso caso, como já 
dissemos, apenas um método para calcular o pagamento a ser feito para os empregados e 
as faturas. O código será apenas: 
public interface Pagamento{ 
 double calcularPagamento(); 
} 
A classe Fatura possui atributos para guardar o nome da peça, o seu preço e a sua 
quantidade. Além disso, implementa o método para calcular o pagamento que foi 
previsto na interface. Seu código está relacionado a seguir: 
public class Fatura implements Pagamento 
{ 
 private String nome; // nome da peça 
 private int quantidade; // quantidade de peças 
 private double preco; // preço unitário da peça 
 public Fatura (String nome, int quantidade, double preco){ 
 this.nome = nome; 
 this.setQuantidade (quantidade); 
 this.setPreco (preco); 
 } 
 public void setNome(String nome){ 
 this.nome = nome; 
 } 
 public String getNome() { 
 return nome; 
 } 
 public void setQuantidade(int quantidade){ 
 this.quantidade = (quantidade<0)? 0 : quantidade; 
 } 
 public int getQuantidade() { 
 return quantidade; 
 } 
 public void setPreco(double preco) { 
 this.preco = ( preco < 0.0 ) ? 0.0 : preco; 
 } 
 public double getPreco() { 
 return preco; 
 } 
 public String toString() { 
 return String.format( 
 "%s: \n%s: %s \n%s: %d \n%s: R$ %.2f", 
 "Fatura", "Nome da Peça", getNome(), "Quantidade", 
 getQuantidade(), "Preço por item", getPreco() ); 
 } 
 public double calcularPagamento () { 
 
 return getQuantidade() * getPreco(); 
 } 
} // fim da classe Fatura 
Na classe Empregado mudaremos apenas a declaração da classe para: 
public abstract class Empregado implements Pagamento { 
 
Nas demais classes de empregados, acrescentaremos um implementação do método 
calcularPagamento() que apenas chama o método salário(). Coloque em cada um dos 
arquivos das classes: 
 public double calcularPagamento () { 
 return salario(); 
 } 
A classe de teste Principal, agora instancia cinco elementos em um array de objetos com 
a mesma interface (Pagamento). Quatro desses objetos são empregados e um é uma 
fatura. Veja o código usando o comando for estendido: 
public class Principal{ // Testando o projeto 
 public static void main ( String argv[]) { 
 Pagamento pagamentos[] = new Pagamento[5];// array 
 pagamentos[0] = new EmpFixoComissionado ("Carlos", 
 "Silva","123456789-10", 10000, 0.02, 300, 0.01); 
 pagamentos[1] = new EmpComissionado ("Francisco", 
 "Matos","987654321-00", 20000, 0.02, 0.01); 
 pagamentos[2] = new EmpAssalariado ("Joaquim", 
 "Alberto", "192837465-99", 1000); 
 pagamentos[3] = new EmpHorista ("Felipe", 
 "Martins", "999888765-43", 100); 
 pagamentos[4] = new Fatura ("Guardanapo",10,1.20); 
 for (Pagamento pagamentoCorrente : pagamentos){ 
 if (pagamentoCorrente instanceof Empregado) { 
 System.out.printf ("%s\n","Empregado:"); 
 } 
 System.out.println(pagamentoCorrente);//toString 
 System.out.printf("Pagamento: R$ %.2f\n\n", 
 pagamentoCorrente.calcularPagamento()); 
 } // fim do for 
 } // fim do método main 
} // fim da classe Principal 
Compile e execute os códigos das classes acima. 
 
 Desafios 
1. Coloque na interface um atributo imposto, no valor de 10%, que deve ser aplicado no 
cálculo do pagamento de todas as classes. Ou seja, o método calcularPagamento deve 
acrescer o percentual de imposto ao valor a ser pago. 
 
2. Observe o modelo abaixo: 
 
 
 
 
 
 
 
 
 
 
Implemente as classes obedecendo à hierarquia do diagrama. A interface Pontuacao define o 
método calcularPontos, que é especificamente implementado em cada classe, obedecendo às 
seguintes regras de negócio: 
a) Os pontos de um cartão de prova são: o número de acertos multiplicado por dois, 
menos o número de erros; 
b) Os pontos de um clube de futebol são o número de vitórias multiplicado por três, 
mais o número de empates; 
c) Os pontos de um clube de investimentos são o número de sócios multiplicado pelo 
investimento médio. 
A classe de teste deve criar um array de três objetos, instanciando um objeto de cada classe 
passando os parâmetros adequados ao construtor. A seguir, deve enviar uma mensagem ao 
objeto pedindo para que este calcule a quantidade de pontos e deve imprimir esse valor 
recebido. 
3. Altere o modelo acima de forma a criar uma segunda interface chamada Peso. Esta nova 
interface será implementada apenas pela classe CartaoProva, que entretanto continuará a 
implementar a interface Pontuacao (ou seja, a classe passará a implementar duas 
interfaces). O objetivo dessa nova interface será definir o peso de cada acerto na 
pontuação da prova. Anteriormente esse peso era dois, pois a quantidade de acertos era 
multiplicada por dois. Agora o atributo PesoDoAcerto, que será definido como 3 na 
interface Peso, será usado para multiplicar pelo número de acertos, antes de diminuir o 
número de erros no método calcularPontos da classe CartaoProva.

Outros materiais