Criar um sistema para gerenciar transações financeiras. Teremos diferentes tipos de Contas (Corrente, Poupança), e o objetivo é que possamos realizar operações comuns, como saque e depósito, de forma polimórfica. Além disso, queremos poder somar (+) o saldo de duas contas de forma intuitiva, independentemente do tipo de conta.
1. Crie uma Interface Abstrata (Conta):
- Crie uma classe base abstrata Conta (usando abc.ABC).
- O construtor (init) deve receber saldo_inicial.
- Defina os métodos abstratos: sacar(valor), depositar(valor) e aplicar_juros().
2. Crie Classes Concretas:
- Crie a classe ContaCorrente que herda de Conta.
- O construtor deve inicializar o saldo e um atributo limite (ex: 500.00).
- Implemente sacar(valor): Deve permitir saque usando o saldo mais o limite. Se o saque usar o limite, imprima um aviso.
- Implemente depositar(valor): Simplesmente aumenta o saldo.
- Implemente aplicar_juros(): Não faz nada (juros não se aplicam a Contas Correntes neste cenário).
- Crie a classe ContaPoupanca que herda de Conta.
- O construtor deve inicializar o saldo.
- Implemente sacar(valor): Permite saque somente se houver saldo suficiente.
- Implemente depositar(valor): Aumenta o saldo.
- Implemente aplicar_juros(): Adiciona um pequeno juro (ex:
do saldo) ao saldo.
3. Polimorfismo (add):
- Em ambas as classes (ContaCorrente e ContaPoupanca), sobrescreva o método add(self, outra_conta).
- Este método deve retornar a soma dos saldos de self e outra_conta.
- Teste:
- Crie instâncias das duas contas.
- Crie uma lista de contas.
- Itere sobre a lista para chamar aplicar_juros() em cada conta (demonstrando polimorfismo por subtipo).
- Use o operador de soma (+) para somar uma ContaCorrente com uma ContaPoupanca (demonstrando polimorfismo de operador).
Passo 1
O enunciado pede que a gente construa um pequeno sistema orientado a objetos para gerenciar transações financeiras com as seguintes exigências principais:
- Criar uma classe base abstrata chamada Conta com construtor que recebe o saldo inicial e três métodos abstratos: sacar(valor), depositar(valor) e aplicar_juros().
- Criar duas subclasses concretas:
- ContaCorrente: tem saldo e um atributo limite (ex.:
); saque pode usar saldo + limite e, caso use o limite, deve exibir um aviso; aplicar_juros() não faz nada. - ContaPoupanca: tem saldo; saque só se houver saldo suficiente; aplicar_juros() adiciona juros de
ao saldo.
- ContaCorrente: tem saldo e um atributo limite (ex.:
- Implementar polimorfismo do operador soma sobrescrevendo o método __add__ em ambas as classes para retornar a soma dos saldos das duas contas.
- Testar: criar instâncias das duas contas, colocar numa lista, iterar chamando aplicar_juros() (polimorfismo por subtipo) e usar o operador + para somar uma ContaCorrente com uma ContaPoupanca (polimorfismo de operador).
Informações relevantes dadas:
- O limite da conta corrente é
(valor exemplo). - A taxa de juros da poupança é
. - Precisamos que saque, depósito e juros funcionem conforme descrito e que __add__ some os saldos.
Passo 2
Conceito e esqueleto da classe abstrata:
- Vamos usar o módulo padrão do Python
abcpara criar uma classe abstrata. Isso força as subclasses a implementarem os métodos essenciais. - A classe
Contaterá:- um construtor que guarda o saldo inicial em
self.saldo; - métodos abstratos
sacar(self, valor),depositar(self, valor)eaplicar_juros(self)decorados com@abc.abstractmethod.
- um construtor que guarda o saldo inicial em
Por que usar
abc.ABC e @abstractmethod?abc.ABCmarca a classe como abstrata: não queremos instanciá-la diretamente.@abstractmethodobriga as subclasses a implementar esses métodos; se uma subclasse não implementar, ela também se torna abstrata e não pode ser instanciada.- Isso ajuda a garantir que qualquer tipo de conta terá as operações básicas (sacar, depositar, aplicar_juros), permitindo polimorfismo.
Exemplo do esqueleto (apenas a interface, sem lógica):
import abc
class Conta(abc.ABC):
def __init__(self, saldo_inicial):
self.saldo = float(saldo_inicial)
@abc.abstractmethod
def sacar(self, valor):
pass
@abc.abstractmethod
def depositar(self, valor):
pass
@abc.abstractmethod
def aplicar_juros(self):
pass
Passo 3
Implementando a classe ContaCorrente:
- Requisitos:
- Construtor deve inicializar
saldoelimite(usaremos por padrão). sacar(valor): permite saque enquantovalor <= self.saldo + self.limite. Sevalorfor maior queself.saldomas menor ou igual asaldo + limite, isso significa que estamos usando parte do limite — aí mostramos um aviso e deixamosself.saldopossivelmente negativo (representando uso do limite).depositar(valor): acrescenta aoself.saldo.aplicar_juros(): não faz nada.__add__(self, outra_conta): retorna a soma dos saldos (número float).
- Construtor deve inicializar
Detalhes de implementação do saque:
- Calcular
disponivel = self.saldo + self.limite. - Se
valor <= self.saldo: basta subtrair do saldo. - Se
self.saldo < valor <= disponivel: subtrair do saldo (pode ficar negativo) e exibir aviso indicando que parte do limite foi usado. - Se
valor > disponivel: rejeitar o saque (fundos insuficientes).
Código da classe:
class ContaCorrente(Conta):
def __init__(self, saldo_inicial, limite=500.0):
super().__init__(saldo_inicial)
self.limite = float(limite)
def sacar(self, valor):
valor = float(valor)
disponivel = self.saldo + self.limite
if valor <= self.saldo:
self.saldo -= valor
print(f"Saque de {valor:.2f} realizado. Saldo restante: {self.saldo:.2f}")
elif valor <= disponivel:
self.saldo -= valor
print(f"Saque de {valor:.2f} realizado. Aviso: utilizado limite. Saldo atual: {self.saldo:.2f}")
else:
print(f"Saque de {valor:.2f} negado. Fundos insuficientes (disponível: {disponivel:.2f}).")
def depositar(self, valor):
valor = float(valor)
self.saldo += valor
print(f"Depósito de {valor:.2f} realizado. Saldo atual: {self.saldo:.2f}")
def aplicar_juros(self):
# Conta corrente não recebe juros neste cenário
pass
def __add__(self, outra_conta):
return self.saldo + outra_conta.saldo
Passo 4
Implementando a classe ContaPoupanca:
- Requisitos:
- Construtor inicializa o
saldo. sacar(valor): só permite sevalor <= self.saldo.depositar(valor): aumentasaldo.aplicar_juros(): aplica juros de— isto é, aumenta o saldo em do valor atual. __add__(self, outra_conta): retorna a soma dos saldos.
- Construtor inicializa o
Como calcular
em código:
-
em decimal. - Novo saldo =
self.saldo * (1 + 0.005).
Código da classe:
class ContaPoupanca(Conta):
def __init__(self, saldo_inicial):
super().__init__(saldo_inicial)
def sacar(self, valor):
valor = float(valor)
if valor <= self.saldo:
self.saldo -= valor
print(f"Saque de {valor:.2f} realizado. Saldo restante: {self.saldo:.2f}")
else:
print(f"Saque de {valor:.2f} negado. Saldo insuficiente (saldo: {self.saldo:.2f}).")
def depositar(self, valor):
valor = float(valor)
self.saldo += valor
print(f"Depósito de {valor:.2f} realizado. Saldo atual: {self.saldo:.2f}")
def aplicar_juros(self):
taxa = 0.005 # corresponde a 0,5%
self.saldo *= (1 + taxa)
print(f"Juros aplicados: {taxa*100:.3f}%. Saldo agora: {self.saldo:.2f}")
def __add__(self, outra_conta):
return self.saldo + outra_conta.saldo
Passo 5
Por que sobrescrever __add__ nas duas classes?
- Polimorfismo de operador: o Python chama
a + bcomoa.__add__(b). Se cada tipo de conta implementa__add__, então a soma funciona independentemente do tipo exato (conta corrente + conta poupança, poupança + poupança etc.). - Aqui
__add__retorna um número (a soma dos saldos). Em soluções mais elaboradas poderíamos retornar uma nova Conta, mas o enunciado pede a soma dos saldos, então retornamos umfloat.
Passo 6
Testando na prática (cenário de exemplo):
- Vamos criar uma ContaCorrente com saldo inicial de
e limite padrão . - Criar uma ContaPoupanca com saldo inicial de
. - Fazer um saque de
na conta corrente (deverá usar parte do limite e exibir aviso). - Tentar sacar
da poupança (deverá ser negado). - Colocar as duas contas numa lista e iterar chamando
aplicar_juros()em cada (mostrando que para corrente nada acontece e para poupança o juros é aplicado). - Somar as duas contas usando
+e imprimir o resultado.
Observe que usamos estes valores apenas para demonstrar o comportamento; você pode alterar na hora de testar.
Passo 7
Código de teste completo (pronto para executar). Esse trecho demonstra a criação das contas, operações e o uso do operador +. Execute em um interpretador Python para ver os prints:
import abc
class Conta(abc.ABC):
def __init__(self, saldo_inicial):
self.saldo = float(saldo_inicial)
@abc.abstractmethod
def sacar(self, valor):
pass
@abc.abstractmethod
def depositar(self, valor):
pass
@abc.abstractmethod
def aplicar_juros(self):
pass
class ContaCorrente(Conta):
def __init__(self, saldo_inicial, limite=500.0):
super().__init__(saldo_inicial)
self.limite = float(limite)
def sacar(self, valor):
valor = float(valor)
disponivel = self.saldo + self.limite
if valor <= self.saldo:
self.saldo -= valor
print(f"Saque de {valor:.2f} realizado. Saldo restante: {self.saldo:.2f}")
elif valor <= disponivel:
self.saldo -= valor
print(f"Saque de {valor:.2f} realizado. Aviso: utilizado limite. Saldo atual: {self.saldo:.2f}")
else:
print(f"Saque de {valor:.2f} negado. Fundos insuficientes (disponível: {disponivel:.2f}).")
def depositar(self, valor):
valor = float(valor)
self.saldo += valor
print(f"Depósito de {valor:.2f} realizado. Saldo atual: {self.saldo:.2f}")
def aplicar_juros(self):
# Conta corrente não recebe juros neste cenário
print("ContaCorrente: sem aplicação de juros.")
def __add__(self, outra_conta):
return self.saldo + outra_conta.saldo
class ContaPoupanca(Conta):
def __init__(self, saldo_inicial):
super().__init__(saldo_inicial)
def sacar(self, valor):
valor = float(valor)
if valor <= self.saldo:
self.saldo -= valor
print(f"Saque de {valor:.2f} realizado. Saldo restante: {self.saldo:.2f}")
else:
print(f"Saque de {valor:.2f} negado. Saldo insuficiente (saldo: {self.saldo:.2f}).")
def depositar(self, valor):
valor = float(valor)
self.saldo += valor
print(f"Depósito de {valor:.2f} realizado. Saldo atual: {self.saldo:.2f}")
def aplicar_juros(self):
taxa = 0.005 # corresponde a 0,5%
self.saldo *= (1 + taxa)
print(f"ContaPoupanca: juros de {taxa*100:.3f}% aplicados. Saldo agora: {self.saldo:.2f}")
def __add__(self, outra_conta):
return self.saldo + outra_conta.saldo
# Demonstração
if __name__ == "__main__":
cc = ContaCorrente(1000.0) # saldo inicial 1000,00; limite padrão 500,00
cp = ContaPoupanca(2000.0) # saldo inicial 2000,00
print(f"Saldo inicial - Conta Corrente: {cc.saldo:.2f}")
print(f"Saldo inicial - Conta Poupança: {cp.saldo:.2f}\n")
# Saque que usa limite na conta corrente
cc.sacar(1300.0) # deve usar parte do limite e mostrar aviso
# Saque negado na poupança
cp.sacar(2100.0) # saldo insuficiente
print()
contas = [cc, cp]
for conta in contas:
conta.aplicar_juros()
print()
print(f"Saldo final - Conta Corrente: {cc.saldo:.2f}")
print(f"Saldo final - Conta Poupança: {cp.saldo:.2f}")
total = cc + cp
print(f"\nSoma dos saldos (cc + cp): {total:.2f}")
Resposta
import abc
class Conta(abc.ABC):
def __init__(self, saldo_inicial):
self.saldo = float(saldo_inicial)
@abc.abstractmethod
def sacar(self, valor):
pass
@abc.abstractmethod
def depositar(self, valor):
pass
@abc.abstractmethod
def aplicar_juros(self):
pass
class ContaCorrente(Conta):
def __init__(self, saldo_inicial, limite=500.0):
super().__init__(saldo_inicial)
self.limite = float(limite)
def sacar(self, valor):
valor = float(valor)
disponivel = self.saldo + self.limite
if valor <= self.saldo:
self.saldo -= valor
print(f"Saque de {valor:.2f} realizado. Saldo restante: {self.saldo:.2f}")
elif valor <= disponivel:
self.saldo -= valor
print(f"Saque de {valor:.2f} realizado. Aviso: utilizado limite. Saldo atual: {self.saldo:.2f}")
else:
print(f"Saque de {valor:.2f} negado. Fundos insuficientes (disponível: {disponivel:.2f}).")
def depositar(self, valor):
valor = float(valor)
self.saldo += valor
print(f"Depósito de {valor:.2f} realizado. Saldo atual: {self.saldo:.2f}")
def aplicar_juros(self):
# Conta corrente não recebe juros neste cenário
print("ContaCorrente: sem aplicação de juros.")
def __add__(self, outra_conta):
return self.saldo + outra_conta.saldo
class ContaPoupanca(Conta):
def __init__(self, saldo_inicial):
super().__init__(saldo_inicial)
def sacar(self, valor):
valor = float(valor)
if valor <= self.saldo:
self.saldo -= valor
print(f"Saque de {valor:.2f} realizado. Saldo restante: {self.saldo:.2f}")
else:
print(f"Saque de {valor:.2f} negado. Saldo insuficiente (saldo: {self.saldo:.2f}).")
def depositar(self, valor):
valor = float(valor)
self.saldo += valor
print(f"Depósito de {valor:.2f} realizado. Saldo atual: {self.saldo:.2f}")
def aplicar_juros(self):
taxa = 0.005 # corresponde a 0,5%
self.saldo *= (1 + taxa)
print(f"ContaPoupanca: juros de {taxa*100:.3f}% aplicados. Saldo agora: {self.saldo:.2f}")
def __add__(self, outra_conta):
return self.saldo + outra_conta.saldo
# Demonstração
if __name__ == "__main__":
cc = ContaCorrente(1000.0) # saldo inicial 1000,00; limite padrão 500,00
cp = ContaPoupanca(2000.0) # saldo inicial 2000,00
print(f"Saldo inicial - Conta Corrente: {cc.saldo:.2f}")
print(f"Saldo inicial - Conta Poupança: {cp.saldo:.2f}\n")
# Saque que usa limite na conta corrente
cc.sacar(1300.0) # deve usar parte do limite e mostrar aviso
# Saque negado na poupança
cp.sacar(2100.0) # saldo insuficiente
print()
contas = [cc, cp]
for conta in contas:
conta.aplicar_juros()
print()
print(f"Saldo final - Conta Corrente: {cc.saldo:.2f}")
print(f"Saldo final - Conta Poupança: {cp.saldo:.2f}")
total = cc + cp
print(f"\nSoma dos saldos (cc + cp): {total:.2f}")