Herança Múltipla E Interfaces

Imagine que um Sistema de Controle do Banco pode ser acessado, além dos Gerentes, pelos Diretores do Banco. Teríamos uma classe Diretor .

class Diretor(Funcionario):
def autentica(self, senha):

verifica se a senha confere

E a classe Gerente :

class Gerente(Funcionario): def autentica(self, senha):

verifica se a senha confere e também se o seu departamento tem acesso

Repare que o método de autenticação de cada tipo de Funcionario pode variar muito. Mas vamos aos problemas. Considere o SistemaInterno e seu controle: precisamos receber um Diretor ou Gerente como argumento, verificar se ele se autentica e colocá-lo dentro do sistema.

Vimos que podemos utilizar a função hasattr() para verificar se um objeto possui o método

autentica() :

class SistemaInterno:
def login(self, funcionario):
if (hasattr(obj, 'autentica')): # chama método autentica
else:
 
# imprime mensagem de ação inválida
 
Mas podemos esquecer, no futuro, quando modelarmos a classe Presidente (que também é um funcionário e autenticável), de implementar o método autentica() . Não faz sentido colocarmos o método autentica() na classe Funcionario já que nem todo funcionário é autenticável.
 

Uma solução mais interessante seria criar uma classe no meio da árvore de herança, a

FuncionarioAutenticavel :

class FuncionarioAutenticavel(Funcionario): def autentica(self, senha):

verifica se a senha confere

E as classes Diretor , Gerente e qualquer outro tipo de FuncionarioAutenticavel que vier a existir em nosso sistema bancário passaria a estender de FuncionarioAutenticavel . Repare que FuncionarioAutenticavel é forte candidata a classe abstrata. Mais ainda, o método autentica() poderia ser um método abstrato.

O uso de herança simples resolve o caso, mas vamos a uma outra situação um pouco mais complexa: todos os clientes também devem possuir acesso ao SistemaInterno . O que fazer?

Uma opção é fazer uma herança sem sentido para resolver o problema, por exemplo, fazer Cliente estender de FuncionarioAutenticavel . Realmente resolve o problema, mas trará diversos outros. Cliente definitivamente não é um FuncionarioAutenticavel . Se você fizer isso, o Cliente terá, por exemplo, um método get_bonificacao() , um atributo salario e outros membros que não fazem o menor sentido para esta classe.

Precisamos, para resolver este problema, arranjar uma forma de referenciar Diretor , Gerente e

Cliente de uma mesma maneira, isto é, achar um fator comum.

Se existisse uma forma na qual essas classes garantissem a existência de um determinado método, através de um contrato, resolveríamos o problema. Podemos criar um “contrato” que define tudo o que uma classe deve fazer se quiser ter um determinado status. Imagine:

contrato Autenticavel

  • quem quiser ser Autenticavel precisa saber fazer: autenticar dada uma senha, devolvendo um booleano

Quem quiser pode assinar este contrato, sendo assim obrigado a explicar como será feita essa autenticação. A vantagem é que, se um Gerente assinar esse contrato, podemos nos referenciar a um Gerente como um Autenticavel .

Como Python admite herança múltipla, podemos criar a classe Autenticavel :

class Autenticavel:
def autentica(self, senha):

verifica se a senha confere

E fazer Gerente , Diretor e Cliente herdarem essa classe:

class Gerente(Funcionario, Autenticavel): # código omitido
class Diretor(Funcionario, Autenticavel): # código omitido
class Cliente(Autenticavel): # código omitido

Ou seja, Gerente e Diretor além de funcionários são autenticáveis! Assim, podemos utilizar o

SistemaInternopara funcionários autenticáveis e clientes:‌

class SistemaInterno: def login(self, obj):
if (hasattr(obj, 'autentica')): obj.autentica()

return True else:

print(f'{} não é autenticável {self. class . name }') return False
if name == ' main ':

diretor = Diretor(‘João’, ‘111111111-11’, 3000.0, ‘1234’)

gerente = Gerente(‘José’, ‘222222222-22’, 5000.0, ‘1235’)

cliente = Cliente(‘Maria’, ‘333333333-33’, ‘1236’)

sistema = SistemaInterno() sistema.login(diretor) sistema.login(gerente) sistema.login(cliente)

Note que uma classe pode herdar de muitas outras classes. Mas vamos aos problemas que isso pode gerar. Por exemplo, várias classes podem possuir o mesmo método.


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