Exercícios da Semana 04: POO

Abstração e Polimorfismo na prática.

O Que Você Vai Aprender

Nesta seção de exercícios, você aplicará os conceitos de classes abstratas e polimorfismo para criar um sistema de armas e demonstrar como diferentes tipos de armas podem ser tratados de forma uniforme através de uma interface comum.

📝 Criar Classes Abstratas

Definir um "contrato" de comportamento para as subclasses.

🔄 Implementar Polimorfismo

Demonstrar como objetos de diferentes classes podem responder ao mesmo método de forma única.

Desafios Propostos

Siga os passos abaixo para construir a hierarquia de classes de armas, implementando abstração e polimorfismo.

  • 1. Crie uma classe abstrata `Arma`

    Com um método abstrato `atacar()`.

    from abc import ABC, abstractmethod
    
    class Arma(ABC):
        def __init__(self, nome):
            self.nome = nome
    
        @abstractmethod
        def atacar(self):
            pass
    
  • 2. Crie subclasses `Espada` e `Arco`

    Ambas devem herdar de `Arma` e implementar o método `atacar()` de maneiras diferentes.

    class Espada(Arma):
        def __init__(self, nome, dano_base):
            super().__init__(nome)
            self.dano_base = dano_base
    
        def atacar(self):
            return f"A {self.nome} causa {self.dano_base} de dano com um golpe cortante!"
    
    class Arco(Arma):
        def __init__(self, nome, tipo_flecha):
            super().__init__(nome)
            self.tipo_flecha = tipo_flecha
    
        def atacar(self):
            return f"O {self.nome} dispara uma flecha ({self.tipo_flecha}) com precisão!"
    
  • 3. Crie uma função `lutar()`

    Que chame `arma.atacar()`, demonstrando o polimorfismo.

    def lutar(personagem, arma):
        print(f"{personagem} usa a {arma.nome} para atacar:")
        print(arma.atacar())
    
    # Exemplo de uso:
    # espada_longa = Espada("Espada Longa", 15)
    # arco_curto = Arco("Arco Curto", "fogo")
    
    # lutar("Cavaleiro", espada_longa)
    # lutar("Arqueiro", arco_curto)
    

Simulador: Sistema de Armas Polimórfico

Crie diferentes armas e um personagem para lutar com elas. Observe como a função `lutar` chama o método `atacar` de forma polimórfica, adaptando-se ao tipo de arma.

Classes `Arma`, `Espada` e `Arco` (simuladas)

As classes e a função `lutar` foram implementadas para simular o comportamento de abstração e polimorfismo em Python, permitindo interações em tempo real.

# Simulação de classes abstratas em Python
from abc import ABC, abstractmethod

# Classe Abstrata: Arma
class Arma(ABC):
    """
    Classe abstrata que serve como um "contrato" para todas as armas.
    Não pode ser instanciada diretamente.
    """
    def __init__(self, nome: str):
        self.nome = nome

    @abstractmethod
    def atacar(self) -> str:
        """
        Método que toda subclasse de Arma é obrigada a implementar.
        """
        pass

# Subclasse: Espada
class Espada(Arma):
    """
    Uma implementação concreta de Arma.
    """
    def __init__(self, nome: str, dano_base: int):
        super().__init__(nome)  # Chama o construtor da classe pai (Arma)
        self.dano_base = dano_base

    def atacar(self) -> str:
        # Implementação específica do ataque para a Espada
        return f"A {self.nome} causa {self.dano_base} de dano com um golpe cortante!"

# Subclasse: Arco
class Arco(Arma):
    """
    Outra implementação concreta de Arma.
    """
    def __init__(self, nome: str, tipo_flecha: str):
        super().__init__(nome)
        self.tipo_flecha = tipo_flecha

    def atacar(self) -> str:
        # Implementação específica do ataque para o Arco
        return f"O {self.nome} dispara uma flecha ({self.tipo_flecha}) com precisão!"

# Função polimórfica
def lutar(personagem: str, arma: Arma):
    """
    Esta função funciona com qualquer objeto que seja uma subclasse de Arma,
    demonstrando o polimorfismo.
    """
    print(f"{personagem} usa a {arma.nome} para atacar:")
    print(arma.atacar())
    print("-" * 20)

# --- Demonstração de uso ---

# 1. Criando instâncias das classes concretas
espada_longa = Espada("Espada Longa de Aço", 15)
arco_elfico = Arco("Arco Élfico", "Flecha de Prata")

# 2. Usando a função polimórfica com diferentes tipos de armas
guerreiro = "Aragorn"
elfo = "Legolas"

lutar(guerreiro, espada_longa)
lutar(elfo, arco_elfico)

# 3. Tentando instanciar a classe abstrata (irá gerar um erro)
try:
    arma_generica = Arma("Arma Genérica")
except TypeError as e:
    print("\nTentativa de instanciar a classe abstrata:")
    print(f"ERRO: {e}")

Criar Armas e Lutar

Selecione uma arma e um personagem para começar a lutar.

Desafios para Continuar

Coloque seus conhecimentos em prática com estes desafios para solidificar sua compreensão sobre classes abstratas e polimorfismo.

  • 1. Adicionar uma nova arma

    Crie uma nova subclasse de `Arma`, por exemplo, `CajadoMagico`, que implemente o método `atacar()` de uma maneira totalmente nova (ex: "lança um feitiço de bola de fogo").

  • 2. Exibir características específicas

    Modifique a função `lutar()` para que, além de chamar `arma.atacar()`, ela também tente exibir uma característica específica da arma se ela existir (ex: `arma.dano_base` para espada, `arma.tipo_flecha` para arco, usando `hasattr()` para verificar).