Objetivos dos Exercícios da Semana 05
Esta semana é dedicada à consolidação dos conceitos de Programação Orientada a Objetos em Python através de exercícios práticos. Ao final, você deverá ser capaz de:
✨ Métodos Mágicos
Implementar e entender o uso de `__str__` e `__eq__` para representação e comparação de objetos.
🧩 Composição
Modelar relações "tem um" entre classes utilizando o conceito de composição.
🚀 Projeto Integrador
Aplicar e combinar todos os pilares da POO (classes, herança, encapsulamento, polimorfismo) em um projeto funcional.
✅ Resolução de Problemas
Desenvolver habilidades de design e resolução de problemas através da prática.
Exercício 1: Implementando `__str__` e `__eq__`
O primeiro exercício foca na personalização do comportamento de seus objetos com métodos mágicos. Você deverá implementar:
- `__str__`: Para fornecer uma representação de string legível para o usuário (como `print()`).
- `__eq__`: Para definir como dois objetos da sua classe são comparados por igualdade (`==`).
Exemplo com a Classe `Pessoa`
# Exercício 1: Implemente __str__ e __eq__
class Pessoa:
def __init__(self, nome, idade, cpf):
self.nome = nome
self.idade = idade
self.cpf = cpf # Assumindo CPF como identificador único
def __str__(self):
# Representação de string amigável para o usuário
return f"Pessoa(Nome: {self.nome}, Idade: {self.idade}, CPF: {self.cpf})"
def __eq__(self, outro):
# Define a igualdade com base no CPF
if not isinstance(outro, Pessoa):
return NotImplemented # Não sabe comparar com outros tipos
return self.cpf == outro.cpf
# Exemplo de uso:
# p1 = Pessoa("Maria Silva", 30, "123.456.789-00")
# p2 = Pessoa("Maria Silva", 30, "123.456.789-00") # Mesma pessoa
# p3 = Pessoa("João Souza", 25, "987.654.321-11")
# print(p1) # Chama __str__
# print(f"p1 == p2: {p1 == p2}") # Chama __eq__ (True)
# print(f"p1 == p3: {p1 == p3}") # Chama __eq__ (False)
# print(f"p1 == 'alguma string': {p1 == 'alguma string'}") # Chama __eq__ (False, devido ao NotImplemented)
Exercício 2: Composição (Classe Carro e Motor)
Este exercício explora o conceito de composição, uma relação "tem um" entre objetos. Em vez de herdar características, um objeto contém outro como parte de si mesmo.
Exemplo: `Carro` "tem um" `Motor`
# Exercício 2: Crie uma classe Carro que use composição (ela deve ter um objeto Motor como atributo).
class Motor:
def __init__(self, tipo, potencia):
self.tipo = tipo
self.potencia = potencia
self.ligado = False
def ligar(self):
self.ligado = True
return "Motor ligado!"
def desligar(self):
self.ligado = False
return "Motor desligado."
def __str__(self):
return f"Motor(Tipo: {self.tipo}, Potência: {self.potencia} HP, Ligado: {self.ligado})"
class Carro:
def __init__(self, marca, modelo, tipo_motor, potencia_motor):
self.marca = marca
self.modelo = modelo
# Composição: Um Carro 'tem um' Motor
self.motor = Motor(tipo_motor, potencia_motor)
self.velocidade = 0
def acelerar(self, incremento):
if self.motor.ligado:
self.velocidade += incremento
return f"Acelerando... Velocidade atual: {self.velocidade} km/h."
return "Motor desligado. Não é possível acelerar."
def frear(self, decremento):
self.velocidade = max(0, self.velocidade - decremento)
return f"Freando... Velocidade atual: {self.velocidade} km/h."
def __str__(self):
status_motor = "ligado" if self.motor.ligado else "desligado"
return (f"Carro({self.marca} {self.modelo}) - Motor: {self.motor.tipo} ({self.motor.potencia} HP, {status_motor}), "
f"Velocidade: {self.velocidade} km/h")
# Exemplo de uso:
# meu_motor = Motor("V8", 400)
# meu_carro = Carro("Ford", "Mustang", "V8", 400) # O Carro cria seu próprio Motor internamente
# print(meu_carro)
# print(meu_carro.motor.ligar()) # Acessa o método do objeto Motor através do Carro
# print(meu_carro.acelerar(50))
# print(meu_carro)
# print(meu_carro.motor.desligar())
# print(meu_carro.acelerar(10)) # Não acelera, motor desligado
Exercício 3: Projeto Final - Integrando Conceitos de POO
Este é o desafio final da semana: juntar tudo o que você aprendeu em um pequeno sistema. O objetivo é aplicar classes, herança, encapsulamento e polimorfismo de forma coesa.
Exemplo: Mini Sistema de Biblioteca
Um sistema de biblioteca simples pode demonstrar todos os pilares da POO:
- Classes: `Livro`, `Membro`, `Biblioteca`.
- Herança: `LivroDigital` e `LivroFisico` herdando de `Livro`.
- Encapsulamento: Usar atributos privados/protegidos (ex: `_titulo`, `_membros_ativos`).
- Polimorfismo: Um método que pode exibir detalhes de qualquer tipo de livro (digital ou físico) ou que pode lidar com diferentes tipos de membros.
# Exercício 3: Projeto Final - Mini Sistema de Biblioteca
# Classe base para Livros
class Livro:
def __init__(self, titulo, autor, ano_publicacao):
# Encapsulamento: Usando prefixo "_" para indicar atributos protegidos
self._titulo = titulo
self._autor = autor
self._ano_publicacao = ano_publicacao
self._disponivel = True
@property # Getter para _titulo
def titulo(self):
return self._titulo
@property # Getter para _autor
def autor(self):
return self._autor
@property # Getter para _ano_publicacao
def ano_publicacao(self):
return self._ano_publicacao
@property # Getter para _disponivel
def disponivel(self):
return self._disponivel
@disponivel.setter # Setter para _disponivel
def disponivel(self, status):
self._disponivel = status
def descrever(self):
return f"Título: {self._titulo}, Autor: {self._autor}, Ano: {self._ano_publicacao}"
def __str__(self):
return self.descrever()
# Herança: LivroDigital e LivroFisico herdam de Livro
class LivroDigital(Livro):
def __init__(self, titulo, autor, ano_publicacao, formato):
super().__init__(titulo, autor, ano_publicacao)
self.formato = formato # ex: PDF, EPUB
def descrever(self):
# Polimorfismo: Sobrescreve o método da classe base
return f"{super().descrever()}, Formato: {self.formato} (Digital)"
class LivroFisico(Livro):
def __init__(self, titulo, autor, ano_publicacao, num_paginas):
super().__init__(titulo, autor, ano_publicacao)
self.num_paginas = num_paginas
def descrever(self):
# Polimorfismo: Sobrescreve o método da classe base
return f"{super().descrever()}, Páginas: {self.num_paginas} (Físico)"
class Membro:
def __init__(self, nome, id_membro):
self.nome = nome
self.id_membro = id_membro
self.livros_emprestados = []
def pegar_emprestado(self, livro):
if livro.disponivel:
self.livros_emprestados.append(livro)
livro.disponivel = False
return f"{self.nome} emprestou '{livro.titulo}'."
return f"'{livro.titulo}' não está disponível."
def devolver(self, livro):
if livro in self.livros_emprestados:
self.livros_emprestados.remove(livro)
livro.disponivel = True
return f"{self.nome} devolveu '{livro.titulo}'."
return f"{self.nome} não tinha '{livro.titulo}' emprestado."
def __str__(self):
return f"Membro(ID: {self.id_membro}, Nome: {self.nome})"
class Biblioteca:
def __init__(self, nome):
self.nome = nome
self._livros = [] # Encapsulamento
self._membros = [] # Encapsulamento
def adicionar_livro(self, livro):
self._livros.append(livro)
print(f"Livro '{livro.titulo}' adicionado à biblioteca.")
def registrar_membro(self, membro):
self._membros.append(membro)
print(f"Membro '{membro.nome}' registrado na biblioteca.")
def listar_livros(self):
print(f"\nLivros na {self.nome}:")
if not self._livros:
print("Nenhum livro cadastrado.")
return
for livro in self._livros:
# Polimorfismo: 'descrever' funciona para Livro, LivroDigital, LivroFisico
status = "Disponível" if livro.disponivel else "Emprestado"
print(f"- {livro.descrever()} | Status: {status}")
def listar_membros(self):
print(f"\nMembros da {self.nome}:")
if not self._membros:
print("Nenhum membro registrado.")
return
for membro in self._membros:
print(f"- {membro}")
if membro.livros_emprestados:
emprestados = ", ".join([livro.titulo for livro in membro.livros_emprestados])
print(f" Livros emprestados: {emprestados}")
else:
print(" Nenhum livro emprestado.")
# Exemplo de uso do Mini Sistema de Biblioteca:
# biblioteca_central = Biblioteca("Biblioteca Central")
# livro_fisico1 = LivroFisico("O Senhor dos Anéis", "J.R.R. Tolkien", 1954, 1200)
# livro_digital1 = LivroDigital("Guia do Mochileiro das Galáxias", "Douglas Adams", 1979, "EPUB")
# livro_fisico2 = LivroFisico("1984", "George Orwell", 1949, 328)
# biblioteca_central.adicionar_livro(livro_fisico1)
# biblioteca_central.adicionar_livro(livro_digital1)
# biblioteca_central.adicionar_livro(livro_fisico2)
# membro1 = Membro("Carlos Alberto", "M001")
# membro2 = Membro("Ana Paula", "M002")
# biblioteca_central.registrar_membro(membro1)
# biblioteca_central.registrar_membro(membro2)
# biblioteca_central.listar_livros()
# biblioteca_central.listar_membros()
# print(membro1.pegar_emprestado(livro_fisico1))
# print(membro2.pegar_emprestado(livro_digital1))
# print(membro1.pegar_emprestado(livro_fisico1)) # Tenta emprestar novamente
# biblioteca_central.listar_livros()
# biblioteca_central.listar_membros()
# print(membro1.devolver(livro_fisico1))
# biblioteca_central.listar_livros()
Simulador Interativo: Exercícios 1 e 2
Use este simulador para interagir com as classes simuladas em JavaScript que demonstram o Exercício 1 (`__str__` e `__eq__` com `Pessoa`) e o Exercício 2 (Composição com `Carro` e `Motor`).
Código Python das Classes Simuladas
# Classes Simuladas para o Exercício 1 (Pessoa)
class Pessoa:
def __init__(self, nome, idade, cpf):
self.nome = nome
self.idade = idade
self.cpf = cpf
def __str__(self):
return f"Pessoa(Nome: {self.nome}, Idade: {self.idade}, CPF: {self.cpf})"
def __eq__(self, outro):
if not isinstance(outro, Pessoa):
return NotImplemented
return self.cpf == outro.cpf
# Classes Simuladas para o Exercício 2 (Carro e Motor)
class Motor:
def __init__(self, tipo, potencia):
self.tipo = tipo
self.potencia = potencia
self.ligado = False
def ligar(self):
self.ligado = True
return "Motor ligado!"
def desligar(self):
self.ligado = False
return "Motor desligado."
def __str__(self):
return f"Motor(Tipo: {self.tipo}, Potência: {self.potencia} HP, Ligado: {self.ligado})"
class Carro:
def __init__(self, marca, modelo, tipo_motor, potencia_motor):
self.marca = marca
self.modelo = modelo
self.motor = Motor(tipo_motor, potencia_motor)
self.velocidade = 0
def acelerar(self, incremento):
if self.motor.ligado:
self.velocidade += incremento
return f"Acelerando... Velocidade atual: {self.velocidade} km/h."
return "Motor desligado. Não é possível acelerar."
def frear(self, decremento):
self.velocidade = max(0, self.velocidade - decremento)
return f"Freando... Velocidade atual: {self.velocidade} km/h."
def __str__(self):
status_motor = "ligado" if self.motor.ligado else "desligado"
return (f"Carro({self.marca} {self.modelo}) - Motor: {self.motor.tipo} ({self.motor.potencia} HP, {status_motor}), "
f"Velocidade: {self.velocidade} km/h")
Simulador - Exercício 1: Classe `Pessoa`
Pessoa 1
Pessoa 2
Simulador - Exercício 2: Composição (Carro e Motor)
Crie seu Carro
Ações do Carro
Próximos Passos: Desafios Finais
Agora que você revisou os exemplos, é hora de aplicar esses conceitos em seus próprios projetos. Os exercícios desta semana são fundamentais para solidificar seu entendimento de POO.
-
1
Exercício 1: Implemente o método `__str__` e `__eq__` na sua classe `Pessoa` ou `Livro`.
Escolha uma das classes que você já criou (ou crie uma nova) e adicione esses métodos mágicos. Teste-os para garantir que funcionam como esperado.
Dica: Lembre-se que `__str__` é para exibição amigável e `__eq__` é para definir o que significa "igualdade" entre dois objetos.
-
2
Exercício 2: Crie uma classe `Carro` que use composição (ela deve ter um objeto `Motor` como atributo).
Defina uma classe `Motor` e inclua uma instância dela como um atributo dentro da sua classe `Carro`. Pense em como o `Carro` interage com o seu `Motor` (ex: ligar/desligar o motor afeta o carro).
Dica: Composição é sobre relações "tem um", enquanto herança é sobre relações "é um".
-
3
Exercício 3: Projeto Final - Junte todos os conceitos.
Crie um pequeno sistema (ex: um mini sistema de biblioteca, um jogo de RPG de texto simples) usando classes, herança, encapsulamento e polimorfismo. O objetivo é demonstrar sua capacidade de integrar todos esses conceitos de forma funcional.
Dica: Comece pequeno! Planeje as classes principais e como elas se relacionarão. Considere as operações que seu sistema precisa realizar (ex: adicionar livro, emprestar, devolver para uma biblioteca; movimentar personagem, atacar para um RPG).