Pular para conteúdo

Aula 14 - Orientação a Objetos (Avançado)

🎯 Objetivos da Aula

  • [ ] Entender o conceito de Herança (Inheritance)
  • [ ] Aplicar Polimorfismo (Polymorphism)
  • [ ] Conhecer o Encapsulamento (variáveis "privadas")
  • [ ] Sobrescrever métodos (super())

📚 Conteúdo

1. Herança (Inheritance)

A Herança permite criar uma nova classe baseada em uma já existente. Ela "herda" todos os atributos e métodos da classe pai (Superclasse).

Exemplo: Um Aluno é uma Pessoa. Um Professor é uma Pessoa. Ambos têm nome e idade, mas fazem coisas diferentes.

classDiagram
    class Pessoa {
        +nome
        +idade
    }
    class Aluno {
        +estudar()
    }
    class Professor {
        +ensinar()
    }
    Pessoa <|-- Aluno
    Pessoa <|-- Professor
class Pessoa: # Classe Pai (Superclasse)
    def __init__(self, nome, idade):
        self.nome = nome
        self.idade = idade

    def se_apresentar(self):
        print(f"Olá, sou {self.nome}.")

class Aluno(Pessoa): # Classe Filha (Subclasse)
    def estudar(self):
        print(f"{self.nome} está estudando.")

# Testando
p1 = Pessoa("Carlos", 40)
a1 = Aluno("Ana", 20)

a1.se_apresentar() # Herdou de Pessoa!
a1.estudar()       # Método exclusivo de Aluno
# p1.estudar()     # ERRO! Pessoa não estuda (genericamente)

2. Polimorfismo

Polimorfismo significa "muitas formas". Classes filhos podem ter o mesmo método da classe pai, mas com comportamento diferente.

class Animal:
    def fazer_som(self):
        print("Som genérico")

class Cachorro(Animal):
    def fazer_som(self): # Sobrescrita (Override)
        print("Au au!")

class Gato(Animal):
    def fazer_som(self):
        print("Miau!")

# A mágica do Polimorfismo
animais = [Cachorro(), Gato(), Animal()]

for bicho in animais:
    bicho.fazer_som()
    # O Python sabe qual método chamar para cada tipo!

3. O Método super()

Às vezes, queremos usar a lógica da classe pai e ADICIONAR algo a mais.

class Aluno(Pessoa):
    def __init__(self, nome, idade, matricula):
        # Chama o construtor da Pessoa para cuidar do nome e idade
        super().__init__(nome, idade)
        self.matricula = matricula # Atributo exclusivo

    def se_apresentar(self):
        super().se_apresentar() # Chama o original
        print(f"Minha matrícula é {self.matricula}")

4. Encapsulamento (Privado vs Público)

Em Python, não existem atributos verdadeiramente "privados" (como em Java), mas temos uma convenção forte:

  • self.nome: Público. Pode ser acessado de qualquer lugar.
  • self._saldo: Protegido. Só deve ser acessado dentro da classe ou subclasses. (Aviso aos programadores: "Cuidado").
  • self.__senha: Privado. O Python muda o nome internamente para dificultar o acesso direto.
class Conta:
    def __init__(self, saldo):
        self.__saldo = saldo # Privado

    def get_saldo(self): # Getter
        return self.__saldo

c = Conta(100)
# print(c.__saldo) # ERRO! Não existe (diretamente)
print(c.get_saldo()) # 100 (Acesso controlado)

💻 Em Prática

Vamos refatorar o sistema bancário com Herança.

class Conta:
    def __init__(self, titular):
        self.titular = titular
        self.saldo = 0

    def depositar(self, valor):
        self.saldo += valor

class ContaCorrente(Conta):
    def sacar(self, valor):
        if valor <= self.saldo:
            self.saldo -= valor
            print("Saque realizado.")
        else:
            print("Saldo insuficiente.")

class ContaPoupanca(Conta):
    def render_juros(self):
        self.saldo *= 1.05 # Rende 5%
        print("Juros aplicados.")

📝 Resumo

  • Herança (class Filho(Pai):): Reutiliza código.
  • Polimorfismo: Métodos com mesmo nome, comportamentos diferentes.
  • super(): Acessa a classe pai.
  • Encapsulamento: Protege dados sensíveis (__var).

🎯 Próximos Passos