Você está na página 1de 4

Programacao orientada a obetos

Introdução
Continuaremos nosso estudo de programação orientada a objetos explicando e demonstrando o
polimorfismo com hierarquias de herança. O polimorfismo permite “programar no geral” em vez de
“programar no específico”. Em particular, o polimorfismo
permite escrever programas que processam objetos que compartilham a mesma superclasse, direta ou
indiretamente, como se todos
fossem objetos da superclasse; isso pode simplificar a programação.
Considere o exemplo de polimorfismo a seguir. Suponha que criamos um programa que simula o
movimento de vários tipos de
animais para um estudo biológico. As classes Peixe, Anfíbio e Pássaro representam os três tipos de animais
sob investigação. Imagine que cada classe estende a superclasse Animal , que contém um método mover e
mantém a localização atual de um animal como
coordenadas x-y. Cada subclasse implementa o método mover. Nosso programa mantém um array Animal
que contém referências
a objetos das várias subclasses Animal . Para simular os movimentos dos animais, o programa envia a
mesma mensagem a cada
objeto uma vez por segundo — a saber, mover. Cada tipo específico de Animal responde a uma
mensagem mover de uma maneira
única — um Peixe poderia nadar um metro, um Anfíbio poderia pular um metro e meio e um Pássaro
poderia voar três metros.
Cada objeto sabe como modificar suas coordenadas x-y de forma adequada para seu tipo específico de
movimento. Contar com o fato
de que cada objeto sabe “fazer a coisa certa” (isto é, faz o que é apropriado a esse tipo de objeto) em
resposta à mesma chamada
de método é o conceito-chave do polimorfismo. A mesma mensagem (nesse caso, mover) enviada a
uma variedade de objetos tem
muitas formas de resultados — daí o termo polimorfismo.
Implementando para extensibilidade
Com o polimorfismo, podemos projetar e implementar sistemas que são facilmente extensíveis —
novas classes podem ser adicionadas com pouca ou nenhuma modificação a partes gerais do
programa, contanto que as novas classes façam parte da hierarquia
de herança que o programa processa genericamente. As novas classes simplesmente se “encaixam”.
As únicas partes de um programa
que devem ser alteradas são aquelas que exigem conhecimento direto das novas classes que
adicionamos à hierarquia. Por exemplo,
se estendermos a classe Animal para criar a classe Tartaruga (que poderia responder a uma mensagem mover
deslizando uma
polegada), precisaremos escrever somente a classe Tartaruga e a parte da simulação que instancia um
objeto Tartaruga. As partes
da simulação que dizem para que cada Animal se mova genericamente podem permanecer as mesmas.
Visão geral do capítulo
Primeiro, discutiremos os exemplos comuns do polimorfismo. Então, fornecemos um exemplo
simples que demonstra o comportamento polimórfico. Usamos referências de superclasse para
manipular tanto objetos de superclasse como objetos de subclasse
polimorficamente.
10.1 Introdução
10.2 Exemplos de polimorfismo
10.3 Demonstrando um comportamento polimórfico
10.4 Classes e métodos abstratos
10.5 Estudo de caso: sistema de folha de pagamento
utilizando polimorfismo
10.5.1 Superclasse abstrata Employee
10.5.2 Subclasse concreta SalariedEmployee
10.5.3 Subclasse concreta HourlyEmployee
10.5.4 Subclasse concreta CommissionEmployee
10.5.5 Subclasse concreta indireta
BasePlusCommissionEmployee
10.5.6 Processamento polimórfico, operador instanceof
e downcasting
10.6 Atribuições permitidas entre variáveis de
superclasse e subclasse
10.7 Métodos e classes final
10.8 Uma explicação mais profunda das questões com
chamada de métodos a partir de construtores
10.9 Criando e utilizando interfaces
10.9.1 Desenvolvendo uma hierarquia Payable
10.9.2 Interface Payable
10.9.3 Classe Invoice
10.9.4 Modificando a classe Employee para implementar a
interface Payable
10.9.5 Modificando a classe SalariedEmployee para
uso na hierarquia Payable
10.9.6 Usando a interface Payable para processar
Invoice e Employee polimorficamente
10.9.7 Algumas interfaces comuns da Java API
10.10 Melhorias na interface Java SE 8
10.10.1 Métodos de interface default
10.10.2 Métodos de interface static
10.10.3 Interfaces funcionais
10.11 (Opcional) Estudo de caso de GUIs e imagens
gráficas: desenhando com polimorfismo
10.12 Conclusão
Resumo | Exercícios de revisão | Respostas dos exercícios de revisão | Questões | Fazendo a diferença
0jhtp.indb 312 07/07/2016 15:19:18

Capítulo 10 Programação orientada a objetos: polimorfismo 313 e interfaces


Em seguida, apresentaremos um estudo de caso que revisita a hierarquia de funcionários da Seção
9.4.5. Desenvolveremos um
aplicativo simples de folha de pagamento que calcula polimorficamente o salário semanal de
diferentes funcionários utilizando o
método earnings de cada funcionário. Embora os vencimentos de cada tipo de funcionário sejam
calculados de uma maneira específica, o polimorfismo permite processar os funcionários “no geral”.
No estudo de caso, expandimos a hierarquia para incluir duas
novas classes — SalariedEmployee (para pessoas que recebem um salário semanal fixo) e HourlyEmployee
(para pessoas que
recebem um salário por hora e horas extras com um valor 50% maior). Declaramos um conjunto
comum de funcionalidades para
todas as classes na hierarquia atualizada em uma classe “abstrata”, Employee, da qual as classes
“concretas” SalariedEmployee,
HourlyEmployee e CommissionEmployee herdam diretamente e a classe “concreta” BasePlusCommissionEmployee que
herda
indiretamente. Como você verá mais adiante, quando invocamos o método earnings de cada funcionário
a partir de uma referência à superclasse Employee (independentemente do tipo de empregado), o
cálculo correto dos vencimentos da subclasse é
realizado por conta das capacidades polimórficas do Java.
Programando no específico
Ocasionalmente, ao realizar o processamento polimórfico, precisamos programar “no específico”.
Nosso estudo de caso de
Employee demonstra que um programa pode determinar o tipo de um objeto em tempo de execução e
atuar sobre esse objeto de maneira correspondente. No estudo de caso, decidimos que
BasePlusCommissionEmployee deve receber 10% de aumento no salário-
-base. Assim, usamos essas capacidades para determinar se um objeto empregado particular é um
BasePlusCommissionEmployee.
Se for, aumentamos o salário-base desse funcionário em 10%.
Interfaces
O capítulo continua com uma introdução a interfaces Java, que são particularmente úteis para atribuir
funcionalidade comum
a classes possivelmente não relacionadas. Isso permite que objetos de classes não relacionadas sejam
processados polimorficamente
— objetos de classes que implementam a mesma interface podem responder às mesmas chamadas de
método de interface. Para
demonstrar a criação e uso de interfaces, modificaremos nosso aplicativo de folha de pagamento para
criar um aplicativo geral de
contas a pagar que pode calcular pagamentos em razão dos funcionários da empresa e as quantias das
faturas a serem cobradas por
mercadorias adquiridas.
10.2 Exemplos de polimorfismo
Consideraremos vários exemplos adicionais de polimorfismo.
Quadriláteros
Se a classe Retângulo é derivada da classe Quadrilátero, então um objeto Retângulo é uma versão mais
específica de
um objeto Quadrilátero. Qualquer operação (por exemplo, calcular o perímetro ou a área) que pode ser
realizada em um objeto Quadrilátero também pode ser realizada em um objeto Retângulo. Essas operações
podem ser realizadas em outros
Quadriláteros, como Quadrados, Paralelogramos e Trapezoides. O polimorfismo ocorre quando um programa
invoca um
método por meio de uma variável de superclasse Quadrilátero — em tempo de execução, a versão correta
da subclasse do método é
chamada com base no tipo de referência armazenado na variável da superclasse. Veremos um
exemplo simples do código que ilustra
esse processo na Seção 10.3.
Objetos espaciais em um videogame
Suponha que projetamos um videogame que manipula os objetos das classes Marciano, Venusiano,
Plutoniano,
NaveEspacial e CanhãoDeLaser. Imagine que cada classe é herdada da superclasse ObjetoEspacial , que contém o
método
desenhar. Cada subclasse implementa esse método. Um programa de gerenciamento de tela mantém uma
coleção (por exemplo,
um array ObjetoEspacial ) de referências a objetos das várias classes. Para atualizar a tela, o gerenciador
de tela envia periodicamente a mesma mensagem a cada objeto — a saber, desenhar. Mas cada objeto
responde de uma maneira própria com base em
sua classe. Por exemplo, um objeto Marciano desenharia a si mesmo em vermelho com olhos verdes e o
número apropriado de antenas. Um objeto NaveEspacial desenharia a si mesmo como disco voador
brilhante prateado. Um objeto CanhãoDeLaser poderia
se desenhar como um feixe vermelho brilhante através da tela. Mais uma vez, a mesma mensagem
(nesse caso, desenhar) enviada
a uma variedade de objetos tem “muitas formas” de resultados.
Um gerenciador de tela poderia utilizar o polimorfismo para facilitar a adição de novas classes a um
sistema com modifica-
ções mínimas no código do sistema. Suponha que queremos adicionar objetos Mercurianos ao nosso
videogame. Para fazer isso,
construiríamos uma classe Mercuriano que estende ObjetoEspacial e fornece sua própria implementação do
método desenhar.
Quando objetos Mercurianos aparecem na coleção ObjetoEspacial , o código do gerenciador de tela invoca o
método desenhar,
exatamente como faz para um ou outro objeto na coleção, independentemente do seu tipo. Assim, os
novos objetos Mercurianos
são simplesmente "conectados" sem nenhuma modificação no código do gerenciador de tela pelo
programador. Portanto, sem modificar o sistema (além de construir novas classes e modificar o código
que cria novos objetos), você pode utilizar o polimorfismo para
incluir convenientemente tipos adicionais que não foram considerados quando o sistema foi criado.