Herança e�classes abstratas
Programação
Orientada a Objetos
(com Python)
Prof. Rodrigo Rocha <rodrigorgs@ufba.br>
Instituto de Computação
Universidade Federal da Bahia
Herança
Herança
Herança é um mecanismo de linguagens OO na qual uma classe (classe derivada) adquire membros de outra classe (classe base)
Na notação UML, representamos a herança com uma seta vazada
3
Nomenclatura
Dizemos que:
4
Animal | Gato |
classe base | classe derivada |
classe mãe | classe filha |
superclasse | subclasse |
Herança em Python
Ao declarar uma classe, escreva o nome de outra classe entre parênteses para estendê-la
No exemplo, Gato herdou o construtor e o método anda da classe Animal
class Animal:
def __init__(self, nome):
self.nome = nome
def anda(self):
print('andando')
class Gato(Animal):
pass
g = Gato("Mingau")
print(g.nome)
g.anda()
5
Exercício: adicione métodos à classe Animal
O que você pode fazer na classe derivada
✅ Acessar atributos e métodos herdados
✅ Adicionar novos atributos e métodos
✅ Redefinir (sobrepor) métodos herdados
❌ Remover membros herdados: não pode
6
Sobreposição (override)
Ocorre quando uma subclasse fornece uma nova implementação para um método herdado
Override = sobrepor, passar por cima
OBS.: É mais comum traduzir override como sobrescrever (o que é um equívoco, pois essa seria a tradução de overwrite). Note que o método original não deixa de existir, então não se trata de sobrescrever.
7
Sobreposição em Python
No exemplo, Gato sobrepõe o método anda da classe Animal
8
class Animal:
def __init__(self, nome):
self.nome = nome
def anda(self):
print('andando')
class Gato(Animal):
def anda(self):
print('engatinhando')
g = Gato("Mingau")
print(g.nome)
g.anda()
super()
Em alguns casos queremos que a nova implementação de um método sobreposto chame a implementação original da superclasse; esta pode ser acessada com super()
9
class Animal:
def __init__(self, nome):
self.nome = nome
def anda(self):
print('andando')
�class Gato(Animal):
def anda(self):
super().anda()
print('engatinhando')
Exercício: crie uma classe Relatorio, com método imprime, e uma subclasse RelatorioProtegido, que recebe um usuário e só permite imprimir o relatório se o usuário for admin.
super().__init__
É uma boa prática chamar o construtor da superclasse, pois ele inicializa os atributos definidos na superclasse
10
class Animal:
def __init__(self, nome):
self.nome = nome
class Gato(Animal):
def __init__(self, nome):
super().__init__(nome + " Miau")
self.vidas = 7
g = Gato("Mingau")
print(g.nome)
Classe object
11
Herança e subtipo (é-um)
A herança define uma relação de subtipo. No exemplo, Gato é um subtipo de Animal, ou seja, toda instância de Gato é também instância de Animal
Dizemos, ainda, que�todo gato é um animal
12
class Animal:
pass
class Gato(Animal):
pass
g = Gato()
print(isinstance(g, Gato)) # True
print(isinstance(g, Animal)) # True
print(isinstance(g, object)) # True
Herança múltipla
Em Python uma classe pode derivar de mais de uma classe (basta escrever a lista de classes separadas por vírgula), o que chamamos de herança múltipla (em Java, por exemplo, isso não é possível).
Não vamos abordar herança múltipla nesta disciplina.
13
Polimorfismo
Conceito: polimorfismo
15
Polimorfismo de subtipo
No código ao lado, animal.anda() pode se referir ao método de cima ou ao método de baixo, pois animal pode ser um objeto da classe Animal ou de uma de suas subclasses*
Se determinado código manipula objetos de uma classe, ele também deve funcionar com objetos de subclasses*
* de forma geral, classes descendentes
16
class Animal:
def anda(self):
print('andando')
class Gato(Animal):
def anda(self):
print('engatinhando')
def passeia(animal):
for i in range(5):
animal.anda()
Duck typing
Em Python e outras linguagens de tipagem dinâmica, não importa o tipo do objeto, e sim quais métodos e atributos ele define. Isso significa que a função passeia funciona com qualquer objeto que possua o método anda(), independentemente de seu tipo.
17
class Animal:
def anda(self):
print('andando')
class Robo:
def anda(self):
print('tac-tac-tac')
def passeia(animal):
for i in range(5):
animal.anda()
“If it walks like a duck and it quacks like a duck, then it must be a duck"
Classes abstratas
Classes abstratas
19
Classes abstratas – exemplo
Tentar instanciar Forma resulta no erro:
TypeError: Can't instantiate abstract class Forma with abstract methods area, perimetro
20
from abc import ABC, abstractmethod
class Forma(ABC):
def __init__(self, cor):
self.cor = cor
@abstractmethod
def area(self):
pass
@abstractmethod
def perimetro(self):
pass
x = Forma("azul") # TypeError
Classes abstratas – exemplo
Quadrado estende e implementa todos os métodos abstratos de Forma. Por isso, é uma classe concreta
21
class Quadrado(Forma):
def __init__(self, cor, lado):
super().__init__(cor)
self.lado = lado
def area(self):
return self.lado ** 2
def perimetro(self):
return 4 * self.lado
q = Quadrado("azul", 10)
Classes abstratas – exemplo
O método concreto imprime_resumo pode chamar métodos abstratos, pois eles serão definidos em classes concretas
Isso permite definir um algoritmo no qual alguns passos ficam em aberto, podendo ser definidos por uma subclasse
22
class Forma(ABC):
def __init__(self, cor):
self.cor = cor
@abstractmethod
def area(self): pass
@abstractmethod
def perimetro(self): pass
def imprime_resumo(self):
print("Área:", self.area())
print("Perímetro:",� self.perimetro())
Protocolos
Protocolos
Ver slides sobre tipagem estática
Em Java e TypeScript é chamado de interface
24
Herança vs composição
Composição: “tem um"
26
Herança: “é um"
27
Herança: “é um"
28
Gato
Animal
Herança: contra-exemplos
29
Herança: contra-exemplos
30
Herança: contra-exemplos
31
q = Quadrado()
q.largura = 3
q.altura = 4
# qual é o valor de q.largura?
Composição: “tem um"
32
Favoreça composição
33
Exemplo: jogo de estratégia em tempo real (com herança)
Classe Pessoa: pode mover-se e atacar
O ataque varia:
Um arqueiro nunca pode virar um guerreiro, pois�um objeto do tipo Arqueiro não pode mudar seu tipo para Guerreiro durante a execução do programa
34
Exemplo: jogo de estratégia em tempo real (com composição)
Agora considere que qualquer pessoa deve poder se locomover a pé ou a cavalo
Classe Pessoa: pode mover-se e atacar, e possui uma Arma
A ação de atacar consiste em usar a Arma
É possível trocar a arma durante o jogo
35
Exemplo
Vamos criar uma classe que imprime e salva o guia de usuário de uma determinada aplicação.
Esse guia pode ser gerado no formato HTML ou no formato Markdown.
36
Alguns padrões de projeto
Padrão de projeto
É uma solução genérica para um problema recorrente referente ao projeto (design) OO
38
🎨
Observer/listener
Problema: quero enviar uma informação para um objeto, mas não tenho referência para ele
Exemplo: quando o carro pega um item, quero avisar ao quadro de pontuação (interessado) que a pontuação deve ser atualizada
Solução: guarde uma lista na qual os interessados se inscrevem para receber avisos
39
🎨
Strategy
Problema: quero poder alterar o comportamento de um objeto em tempo de execução
Exemplo: ao bater em um obstáculo, o carro deve ser danificado; ao pegar um item de invencibilidade, no entanto, ele deve destruir o obstáculo
Solução: Carro deve possuir um objeto com um método que define o que deve ser feito ao bater em um obstáculo. Esse objeto pode ser trocado (por exemplo, através de um setter).
40
🎨