O Que Você Vai Aprender
Nesta aula, você mergulhará no Pilar do Polimorfismo, o quarto e último pilar da Programação Orientada a Objetos. Entenderá a capacidade de objetos de diferentes classes serem tratados da mesma forma, desde que compartilhem uma superclasse ou um comportamento comum. Você também conhecerá o conceito de "Duck Typing", fundamental em Python.
🦆 Conceito de Polimorfismo
Compreender a ideia de "muitas formas" e como objetos podem se comportar diferentemente com o mesmo método.
🔍 Duck Typing em Python
Aprender como Python foca no comportamento dos objetos, e não no seu tipo explícito.
Conceito: O Pilar do Polimorfismo
O Polimorfismo, do grego "poli" (muitas) e "morfos" (formas), é a capacidade de objetos de diferentes classes responderem ao mesmo nome de método de maneiras distintas, de acordo com sua própria implementação. Isso é possível quando essas classes compartilham uma superclasse comum ou uma interface (um conjunto de métodos).
Polimorfismo Através da Herança e Sobrescrita
A forma mais comum de polimorfismo em linguagens orientadas a objetos, incluindo Python, é alcançada através da herança e da sobrescrita de métodos. Uma superclasse define um método genérico, e suas subclasses fornecem implementações específicas para esse mesmo método.
class Animal:
def fazer_som(self):
print("Som genérico de animal")
class Gato(Animal):
def fazer_som(self): # Sobrescrevendo o método
print("Miau!")
class Cachorro(Animal):
def fazer_som(self): # Sobrescrevendo o método
print("Au Au!")
# Criando uma lista de animais de diferentes tipos
gato = Gato()
cachorro = Cachorro()
animais = [gato, cachorro]
# Iterando sobre a lista e chamando o mesmo método 'fazer_som()'
for animal in animais:
animal.fazer_som() # O mesmo chamado de método se comporta de forma diferente
# Saída:
# Miau!
# Au Au!
Benefícios do Polimorfismo
- **Flexibilidade e Generalização:** Você pode escrever código que opera em objetos de uma superclasse, e ele automaticamente funcionará com qualquer subclasse, sem precisar de `if/else` para cada tipo.
- **Reusabilidade:** Permite criar código mais genérico e reutilizável.
- **Manutenibilidade:** Facilita a adição de novas classes à hierarquia sem modificar o código existente que já utiliza o polimorfismo.
Duck Typing em Python
Python é uma linguagem de tipagem dinâmica e adota o conceito de Duck Typing. A frase famosa que resume isso é: "Se anda como um pato e faz quack como um pato, então é um pato."
O Que Significa?
Em Python, o que importa não é o tipo explícito de um objeto (se ele é um `Gato` ou um `Cachorro`), mas sim o seu comportamento (quais métodos ele possui e como eles são implementados). Se um objeto tem um método `fazer_som()`, Python não se preocupa se ele herda de `Animal` ou não; ele simplesmente tentará chamar `fazer_som()`.
class Pato:
def fazer_som(self):
print("Quack!")
def nadar(self):
print("Nadando como um pato.")
class Pessoa:
def fazer_som(self):
print("Olá!")
# Pessoa não tem método 'nadar'
def interagir_com_som(animal):
# Não importa se 'animal' é um Pato, Gato ou Pessoa,
# contanto que ele tenha o método 'fazer_som()'
animal.fazer_som()
pato = Pato()
pessoa = Pessoa()
interagir_com_som(pato) # Saída: Quack!
interagir_com_som(pessoa) # Saída: Olá!
Implicações do Duck Typing
- **Mais Flexibilidade:** Permite que você escreva código mais flexível, que funciona com qualquer objeto que se "comporte" de uma certa maneira.
- **Menos Acoplamento:** As classes não precisam estar rigidamente ligadas por herança para usar o polimorfismo.
- **Requer Cuidado:** Embora flexível, exige que o programador saiba quais métodos os objetos que ele está usando devem ter, para evitar erros em tempo de execução.
Simulador: Polimorfismo com Veículos
Crie diferentes tipos de veículos e veja como o método `mover()` se comporta de forma polimórfica, mesmo sendo chamado da mesma maneira para todos.
Classes `Veiculo`, `Carro` e `Bicicleta` (simuladas)
class Veiculo:
def __init__(self, nome):
self.nome = nome
def mover(self):
return f"O {self.nome} está se movendo de forma genérica."
class Carro(Veiculo):
def __init__(self, nome, velocidade_max):
super().__init__(nome)
self.velocidade_max = velocidade_max
def mover(self): # Sobrescrito
return f"O carro {self.nome} está acelerando a {self.velocidade_max} km/h."
class Bicicleta(Veiculo):
def __init__(self, nome, tipo_marcha):
super().__init__(nome)
self.tipo_marcha = tipo_marcha
def mover(self): # Sobrescrito
return f"A bicicleta {self.nome} está pedalando com marcha {self.tipo_marcha}."
# Lista polimórfica:
# veiculos = [Carro("Fusca", 120), Bicicleta("Caloi", "manual")]
# for v in veiculos:
# print(v.mover())
Teste o Comportamento Polimórfico
Desafios para Continuar
Coloque seus conhecimentos em prática com estes desafios para solidificar sua compreensão sobre polimorfismo e Duck Typing.
-
✓
1. Crie uma Função Polimórfica de Pagamento
Crie uma superclasse `Pagamento` com um método `processar_pagamento()`. Crie subclasses `CartaoCredito` e `PayPal`, cada uma sobrescrevendo `processar_pagamento()` para exibir uma mensagem específica do método de pagamento.
Em seguida, crie uma função `realizar_transacao(forma_pagamento)` que receba um objeto de pagamento e chame `forma_pagamento.processar_pagamento()`. Teste a função com instâncias de `CartaoCredito` e `PayPal`.
-
✓
2. Demonstre Duck Typing com `Voar`
Crie duas classes: `Pato` e `Aviao`. Ambas as classes devem ter um método `voar()` que imprima uma mensagem específica para cada um (ex: "O pato está voando!" e "O avião está voando!").
Crie uma função `fazer_voar(objeto)` que receba um objeto e chame `objeto.voar()`. Demonstre que esta função funciona tanto para `Pato` quanto para `Aviao`, apesar de não haver uma superclasse comum `Voador`.