Polimorfismo Prof. Marcelo Roberto Zorzan Classe Abstrata ou Interface? • Foi desenvolvida uma aplicação Java para registrar as principais funcionalidades dos instrumentos musicais da orquestra sinfônica do IFSP-PEP. A orquestra hoje é formada por uma equipe de 4 músicos, sendo cada um especializado em um instrumento: guitarra, bateria, baixo e violão. Para que cada instrumento funcionasse corretamente foi registrado na aplicação que ele deveria ser afinado e além disso que fosse possível tocar todas as notas. Um ano depois da aplicação ter sido concluída foi solicitado pela orquestra adicionar uma nova funcionalidade ao sistema de limpar o instrumento. Para este cenário seria melhor usar classe abstrata ou interface? Por quê? Classe Abstrata ou Interface? Uma das vantagens do uso de classes abstratas ao invés de interfaces é a possibilidade de incluir um novo método sem quebrar as classes que estão utilizando a classe abstrata, desde que o método seja concreto. No caso de interfaces, as classes antigas não estariam implementando o novo método e portanto não compilariam mais. Portanto, uma vez que a interface é liberada e está sendo usada amplamente, é quase impossível alterá-la, e por isso é necessário estudar cuidadosamente logo de início como ela deve ser. Classe Abstrata ou Interface? Assim, a regra geral é que uma interface é a melhor forma de definir um tipo que permite múltiplas implementações. Uma exceção a essa regra é o caso em que a facilidade de evolução é considerada mais importante do que a flexibilidade. Aula de Hoje Polimorfismo O que é polimorfismo? Polimorfismo significa "várias formas", ou seja, significa que uma determinada "coisa" pode ser feita de várias maneiras diferentes. Uma analogia ao polimorfismo é o sinal dos colégios. Embora seja um único sinal, ele significa coisas diferentes para cada aluno: uns vão para casa, outros para biblioteca, outros para o boteco alguns poucos voltam para sala de aula, Todos respondem ao sinal, mas cada um do seu jeito. O que é polimorfismo? Polimorfismo significa que diferentes tipos de objetos podem responder a uma mesma mensagem de diferentes maneiras Classificação Polimorfismo Inclusão Em OO, polimorfismo significa que podem existir várias formas de se fazer chamadas de métodos. Quem decide "a forma" de fazer é o objeto que recebe a chamada. Uma forma mais simples de explicar o conceito de polimorfismo é dizer que uma variável de uma dada classe representa não só os objetos dessa classe, mas também os objetos de todas as suas subclasses Inclusão Exemplo: Empregado Diretor Professor Tecnico Se um Diretor é um Empregado, o conceito de polimorfismo diz que uma variável do tipo Empregado pode guardar um objeto do tipo Diretor. O mesmo vale para Professor e Tecnico Empregado[] empregados = new Empregado[4]; empregados[0] = new Empregado(”Luis Silva", 10000); empregados[1] = new Diretor(”Carlos Andrada", 90000, 10); empregados[2] = new Professor(”João Vale Tudo", 70000, “Auxiliar”); empregados[3] = new Tecnico(”Pimenta Machado", 50000, 1); Inclusão Exemplo: Empregado Diretor Professor Tecnico E se a classe Empregado for abstrata? Empregado[] empregados = new Empregado[4]; empregados[0] = new Empregado(”Luis Silva", 10000); (ERRO!!!) empregados[1] = new Diretor(”Carlos Andrada", 90000, 10); empregados[2] = new Professor(”João Vale Tudo", 70000, “Auxiliar”); empregados[3] = new Tecnico(”Pimenta Machado", 50000, 1); Inclusão Para exibir o salário de todos os empregados (diretor, professor e técnico) bastaria utilizar o seguinte código: for (int i= 0; i < empregados.length; i++) empregados[i].exibirSalario(); Inclusão - exemplo Animal emitirSom():void Cachorro Gato Pato emitirSom():void emitirSom():void emitirSom():void Inclusão - exemplo public abstract class Animal Animal.java { Animal(){} public abstract void emitirSom(); } public class Cachorro extends Animal { public Cachorro(){} public void emitirSom() { System.out.println("Au, Au!!!"); } } Cachorro.java Inclusão - exemplo public class Gato extends Animal { public Gato(){} public void emitirSom() { System.out.println(“Miau!!!"); } } Gato.java Inclusão - exemplo public class Pato extends Animal { public Pato(){} public void emitirSom() { System.out.println(“Quack!!!"); } } Pato.java Inclusão - exemplo public class UsandoPolimorfismoComAnimais{ public static void main(String[] args) { Animal [] animais = new Animal[3]; animais[0] = new Cachorro(); animais[1] = new Gato(); animais[2] = new Pato(); ... UsandoPolimorfismoComAnimais.java Inclusão - exemplo ... // Vamos fazer uma brincadeira agora. A gente enfia a mão // na gaiola (não vale olhar), pega um bicho e aperta o // pescoço dele pra ver que som sairá. // Pra fazer isso em Java, a coisa é um pouquinho mais // chata, a tem que usar um mecanismo pra escolher um // desses bichos de forma aleatória. // Vamos então usar um esquema randômico de seleção – a // classe do Java chamada Randow. Esta parte do código para // seleção é de pouca importância para o assunto de hoje... Random seleciona = new Random(); Animal animalEscolhido; Inclusão - exemplo ... // Enfiando a mão na gaiola... for (int i = 0; i < 5; i++) { // Pega aleatoriamente um bicho de cada vez da gaiola. animalEscolhido=gaiolao[seleciona.nextInt(3)]; // Aqui o animal escolhido emitirá o seu som... // Estamos apertando um pescoço agora... animalEscolhido.emitirSom(); } } } Inclusão - exemplo O resultado deste código seria algo como: Miau!!! Au, Au!!! Quack!!! Coerção “Downcast” - Sempre verificado - Explícito “Upcast” - Sempre seguro - Automático (aplicação do polimorfismo) Empregado Downcast Upcast Diretor Professor Tecnico Coerção Upcast: conversão de um tipo específico para um tipo mais genérico Pai Dado o código: Pai p = new Filha(); p é uma referência da superclasse Pai apontando para um objeto subclasse Filha Observe as seguintes instruções: 1.p.m1(); // chama m1( ) da classe Filha 2.p.m2(); // chama m2( ) da classe Pai, herdado por Filha 3.p.m3(); // ERRO de compilação m1() : void m2() : void Filha m1() : void m3() : void Coerção “Uma referência de superclasse só reconhece membros disponíveis na superclasse, mesmo que esteja apontando para um objeto de subclasse.” A Filha herda do Pai todo o seu conhecimento (atributos não privados) e comportamentos (métodos), mas pode acrescentar conhecimento e comportamentos novos exclusivamente seus, aos quais o Pai não tem acesso. A parte escura da figura mostra o que o Pai sabe. Pai Filha Coerção Resumo: upcast é a conversão de um objeto de tipo mais específico para um tipo mais genérico, feita implicitamente através de atribuição, mas a partir da conversão só os membros do tipo mais genérico podem ser acessados. Coerção Downcast: conversão de um tipo genérico para um tipo mais específico O relacionamento É UM é sempre da subclasse para a superclasse. Logo um objeto da classe Pai não é um objeto da classe Filha. Pai p = new Filha(); Filha f = p; // Erro Pode-se "forçar a barra" através de coerção, se soubermos que o objeto atualmente com referência de superclasse é, na realidade, um objeto da subclasse para a qual estamos convertendo. Coerção O downcast é realizado utilizando o operador casting de classes. 1. Pai p = new Filha(); 2. Filha f = (Filha) p; //nome da classe destino entre parênteses 3. f.m3(); O código acima será verificado em tempo de execução. Se o objeto for da subclasse, a coerção será válida, mas se não for, ocorrerá um erro. Para proteger o código dessa incerteza deve-se usar o operador especial instanceof Coerção O operador instanceof deve ser usado como segue: variavelObjeto instanceof NomeClasse 1. Pai p = new Filha(); 2. if (p instanceof Filha){ 3. Filha f = (Filha) p; 4. f.m3(); 5. } Coerção Exemplo de conversão e seus erros: Animal Macaco Girafa Animal a; Macaco m; Girafa g; m = new Macaco(); a = m; g = (Girafa) m; //Erro em tempo de compilação g = (Girafa) a; //Erro em tempo de execução Exercício Crie uma classe Disciplina que possua como atributos: nome, período, nota1, nota2 e o método avaliarDisciplina(). • • • Estenda a classe Disciplina, utilizando herança através das classes DisciplinaTrimestral, DisciplinaSemestral e DisciplinaAnual. DisciplinaTrimestral não tem atributos adicionais e calcula o método avaliarDisciplina() pela fórmula: (nota1 x 0.4) + (nota2 x 0.6). DisciplinaSemestral tem como atributo adicional nota3 e calcula o método avaliarDisciplina() pela formula: (nota1 + nota2 + nota3) / 3.0. DisciplinaAnual possui como atributos adicionais nota3, nota4, nota5 e nota6; e calcula o método avaliarDisciplina() pela fórmula: ((nota1 + nota2 + nota3 + nota4 + nota5) / 5.0 x 0.6) + (nota6 x 0.4). Exercício Crie uma aplicação que contenha uma Disciplina Trimestral, Disciplina Semestral e Disciplina Anual. Defina um método polimórfico para imprimir o resultado retornado pelo método avaliarDisciplina().