12.6 (Opcional) Exercícios - Interfaces E Classes Abstratas

  1. Nosso banco precisa tributar dinheiro de alguns bens que nossos clientes possuem. Para isso, vamos criar uma classe Tributavel no módulo tributavel.py, e adicionar um método que devolve o imposto sobre a conta:
class Tributavel:
python
def get_valor_imposto(self): pass
 

Lemos essa classe da seguinte maneira: “todos que quiserem ser tributáveis precisam saber retornar o valor do imposto”. Alguns bens são tributáveis e outros não, ContaPoupanca não é tributável, já para ContaCorrente você precisa pagar 1% da conta e o SeguroDeVida tem uma faixa fixa de 50 reais mais 5% do valor do seguro.

  1. Torne a classe Tributavel uma classe abstrata:
import abc
python
class Tributavel(abc.ABC):
python
def get_valor_imposto(self) pass
 
3. O método get_valor_imposto() também deve ser abstrato:
 
python
import abc
python
class Tributavel(abc.ABC):

@abc.abstractmethod

def get_valor_imposto(self, valor): pass
 
  1. Nada impede que os usuários de nossa classe tributavel implementem o método get_valor_imposto de maneira não esperada por nós. Então, vamos acrescentar a documentação utilizando docstring que aprendemos no capítulo de módulos:
import abc
python
class Tributavel(abc.ABC):

""" Classe que contém operações de um objeto autenticável

As subclasses concretas devem sobrescrever o método get_valor_imposto. """

@abc.abstractmethod

def get_valor_imposto(self):
 

""" aplica taxa de imposto sobre um determinado valor do objeto """ pass

  1. Utiliza a função help() passando a classe Tributavel para acessar a documentação.

  2. Faça a classe ContaCorrente herdar da classe Tributavel :

class ContaCorrente(Conta, Tributavel): # código omitido
python
def get_valor_imposto(self): return self._saldo \* 0.01
 
7. Crie a classe SeguroDeVida , com os atributos valor , titular e numero_apolice , que também deve ser um tributável. Implemente o método get_valor_imposto() de acordo com a regra de negócio definida pelo exercício:
 
python
class SeguroDeVida(Tributavel):
python
def __init__(self, valor, titular, numero_apolice): self._valor = valor
 
self._titular = titular self._numero_apolice = numero_apolice
 
def get_valor_imposto(self): return 50 + self._valor \* 0.05
 
8. Vamos criar a classe ManipuladorDeTributaveis em um arquivo chamado *manipulador_tributaveis.py*. Essa classe deve ter um método chamado calcula_impostos() que recebe umas lista de tributáveis e retorna o total de impostos cobrados:
 
python
class ManipuladorDeTributaveis:
python
def calcula_impostos(self, lista_tributaveis): total = 0
 

for t in lista_tributaveis:

total += t.get_valor_imposto()
 
return total
 
  1. Nossas classes ContaCorrente e SeguroDeVida já implementam o método

get_valor_imposto() . Vamos instanciar cada umas delas e testar a chamada do método:

if name == ' main ':

cc = ContaCorrente(‘123-4’, ‘João’, 1000.0) seguro = SeguroDeVida(100.0, ‘José’, ‘345-77’)

print(cc.get_valor_imposto()) print(seguro.get_valor_imposto())
  1. Crie uma lista com os objetos criados no exercício anterior, instancie um objeto do tipo list e passe a lista chamando o método calcula_impostos() .
if name == ' main ':

código omitido

lista_tributaveis = [] lista_tributaveis.append(cc) lista_tributaveis.append(seguro)

mt = ManipuladorDeTributaveis()

total = mt.calcula_impostos(lista_tributaveis) print(total)

  1. Nosso código funciona, mas ainda estamos utilizando herança múltipla! Vamos melhorar nosso código. Faça com que ContaCorrente e SeguroDeVida não mais herdem da classe Tributavel :
class ContaCorrente(Conta): # código omitido
python
class SeguroDeVida: # código omitido

Vamos registrar nossas classes ContaCorrente e SeguroDeVida como subclasses virtuais de

Tributavel , de modo que funcione como uma interface.

if name == ' main ':
python
from tributavel import Tributavel

cc = ContaCorrente(‘João’, ‘123-4’) cc.deposita(1000.0)

seguro = SeguroDeVida(100.0, ‘José’, ‘345-77’)

Tributavel.register(ContaCorrente) Tributavel.register(SeguroDeVida)

lista_tributaveis = [] lista_tributaveis.append(cc) lista_tributaveis.append(seguro)

mt = ManipuladorDeTributaveis()

total = mt.calcula_impostos(lista_tributaveis) print(total)

  1. Modifique o método calcula_impostos() da classe ManipuladorDeTributaveis para checar se os elementos da listas são tributáveis através do método isinstance() . Caso um objeto da lista não seja um tributável, vamos imprimir uma mensagem de erro e apenas os tributáveis serão somados ao total:
class ManipuladorDeTributaveis:
python
def calcula_impostos(self, lista_tributaveis): total = 0
 

for t in lista_tributaveis:

if (isinstance(t, Tributavel)): total += t.get_valor_imposto()

else:
 
java
print(t. repr (), "não é um tributável") return total

Teste novamente com a lista de tributáveis que fizemos no exercício anterior e veja se tudo continua funcionando.

  1. ContaPoupanca não é um tributável. Experimente instanciar uma ContaPoupanca , adicionar a lista de tributáveis e calcular o total de impostos através do ManipuladorDeTributaveis :
if name == ' main ':

código omitido do exercício anterior omitido

cp = ContaPoupanca(‘123-6’, ‘Maria’) lista_tributaveis.append(cp)

total = mt.calcula_impostos(lista_tributaveis) print(total)

O que acontece?

  1. (Opcional) Agora, além de ContaCorrente e SeguroDeVida , nossa ContaInvestimento

também deve ser um tributável, cobrando 3% do saldo. Instancie uma ContaInvestimento .

class ContaInvestimento(Conta): def atualiza(self, taxa):

self._saldo += self._saldo * taxa *

def get_valor_imposto(self): return self._saldo \* 0.03
 

Registre a classe ContaInvestimento como tributável. Adicione a ContaInvestimento criada na lista de tributáveis do exercício anterior e calcule o total de impostos através do ManipuladorDeTributaveis .

if name == " main ": # código omitido

ci = ContaInvestimento(‘Ana’, ‘123-0’) ci.deposita(100.0) Tributavel.register(ContaInvestimento)

lista_tributaveis.append(ci) mt = ManipuladorDeTributaveis()

total = mt.calcula_impostos(lista_tributaveis) print(total)

Neste capítulo, aprendemos sobre herança múltipla e suas desvantagens mesmo utilizando mix-ins. Além disso, aprendemos a utilizar classes abstratas como interfaces registrando as classes e evitando os problemas com a herança múltipla. Agora nossa classe abstrata Tributavel funciona como um protocolo. No capítulo sobre o módulo collections, veremos na prática alguns conceitos vistos neste capítulo.

CAPÍTULO 13‌


⬅️ Capítulo Anterior | Próximo Capítulo ➡️