💻 Exemplos: Capítulo 09: Herança, Polimorfismo, Classes Abstratas (abc.ABC) e MRO
Especialização em Sistemas com Python 3.12+ • Capítulo 09
🎯 Demonstração Prática: Gateway de Pagamentos com Template Method, Mixins e MRO
O exemplo abaixo implementa uma arquitetura de pagamentos polimórfica:
- Classe base abstrata herdando de
abc.ABCcom métodos obrigatórios decorados por@abstractmethod. - Implementação do padrão de projeto Template Method (
processar_transacao()), que padroniza o ciclo de vida transacional. - Inclusão do
AuditavelMixindemonstrando herança múltipla, chamadas cooperativas viasuper()e exibição do MRO (Method Resolution Order). - Subclasses especializadas (
ProcessadorPIX,ProcessadorCartaoCredito,ProcessadorBoleto).
"""
demonstracao_heranca_e_polimorfismo.py
Gateway Transacional Polimórfico com abc.ABC, Template Method e Mixin.
Compatível com Python 3.12+.
"""
from __future__ import annotations
from abc import ABC, abstractmethod
from dataclasses import dataclass
from datetime import datetime, timezone
from decimal import Decimal, ROUND_HALF_EVEN
from typing import Final
# ==============================================================================
# 1. MIXIN ORTOGONAL DE AUDITORIA
# ==============================================================================
class AuditavelMixin:
"""Confere recursos de rastreabilidade temporal sem poluir o domínio."""
def registrar_log(self, mensagem: str) -> None:
instante = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC")
print(f" [AUDITORIA][{instante}][{self.__class__.__name__}] {mensagem}")
# ==============================================================================
# 2. DADOS E SUPERCLASSE ABSTRATA (TEMPLATE METHOD PATTERN)
# ==============================================================================
@dataclass(slots=True)
class ReciboTransacao:
id_operacao: str
canal: str
valor_bruto: Decimal
tarifa_processamento: Decimal
valor_liquido: Decimal
sucesso: bool
mensagem_status: str
class GatewayPagamento(ABC, AuditavelMixin):
"""
Superclasse abstrata que orquestra o Template Method de liquidação.
Subclasses concretas definem o cálculo de taxas e a validação específica.
"""
def __init__(self, identificador_canal: str) -> None:
self.identificador_canal: str = identificador_canal
@property
@abstractmethod
def taxa_percentual(self) -> Decimal:
"""Alíquota cobrada pelo adquirente."""
...
@property
@abstractmethod
def tarifa_fixa(self) -> Decimal:
"""Tarifa fixa por evento de liquidação."""
...
@abstractmethod
def validar_dados_transacao(self, valor: Decimal, metadados: dict[str, str]) -> bool:
"""Passo customizado de validação de parâmetros."""
...
# O TEMPLATE METHOD (Esqueleto invariante de execução)
def processar_transacao(
self,
id_operacao: str,
valor: Decimal,
metadados: dict[str, str]
) -> ReciboTransacao:
"""Orquestra as etapas de validação, desconto, liquidação e log de auditoria."""
self.registrar_log(f"Iniciando liquidação para operação {id_operacao} (R$ {valor:,.2f})")
if valor <= Decimal("0.00"):
self.registrar_log(f"Falha de validação: Valor da operação deve ser positivo.")
return ReciboTransacao(
id_operacao=id_operacao, canal=self.identificador_canal,
valor_bruto=valor, tarifa_processamento=Decimal("0.00"),
valor_liquido=Decimal("0.00"), sucesso=False,
mensagem_status="VALOR_INVALIDO"
)
if not self.validar_dados_transacao(valor, metadados):
self.registrar_log(f"Falha de validação: Parâmetros contratuais rejeitados.")
return ReciboTransacao(
id_operacao=id_operacao, canal=self.identificador_canal,
valor_bruto=valor, tarifa_processamento=Decimal("0.00"),
valor_liquido=Decimal("0.00"), sucesso=False,
mensagem_status="METADADOS_REJEITADOS"
)
# Cálculo da taxa polimórfica
taxa_variavel = (valor * self.taxa_percentual).quantize(Decimal("0.01"), ROUND_HALF_EVEN)
custo_total = taxa_variavel + self.tarifa_fixa
valor_liquido = valor - custo_total
self.registrar_log(f"Operação aprovada com sucesso! Custo total: R$ {custo_total:.2f}")
return ReciboTransacao(
id_operacao=id_operacao,
canal=self.identificador_canal,
valor_bruto=valor,
tarifa_processamento=custo_total,
valor_liquido=valor_liquido,
sucesso=True,
mensagem_status="LIQUIDADO_COM_SUCESSO"
)
# ==============================================================================
# 3. SUBCLASSES CONCRETAS POLIMÓRFICAS
# ==============================================================================
class ProcessadorPIX(GatewayPagamento):
def __init__(self) -> None:
super().__init__(identificador_canal="PIX_INSTANTANEO")
@property
def taxa_percentual(self) -> Decimal:
return Decimal("0.0099") # 0.99%
@property
def tarifa_fixa(self) -> Decimal:
return Decimal("0.00")
def validar_dados_transacao(self, valor: Decimal, metadados: dict[str, str]) -> bool:
return "chave_pix" in metadados and len(metadados["chave_pix"]) >= 5
class ProcessadorCartaoCredito(GatewayPagamento):
def __init__(self, parcelas: int = 1) -> None:
super().__init__(identificador_canal=f"CARTAO_CREDITO_{parcelas}X")
self.parcelas: int = parcelas
@property
def taxa_percentual(self) -> Decimal:
# 2.5% à vista, +1.0% por parcela adicional
return Decimal("0.025") + (Decimal("0.01") * Decimal(str(self.parcelas - 1)))
@property
def tarifa_fixa(self) -> Decimal:
return Decimal("0.65") # Custo de gateway antifraude
def validar_dados_transacao(self, valor: Decimal, metadados: dict[str, str]) -> bool:
return "token_cartao" in metadados and metadados.get("cvv_validado") == "true"
# ==============================================================================
# 4. EXECUÇÃO DEMONSTRATIVA E INSPEÇÃO DE MRO
# ==============================================================================
if __name__ == "__main__":
print("=" * 80)
print(" GATEWAY POLIMÓRFICO COM TEMPLATE METHOD E C3 MRO")
print("=" * 80)
# Exibição do MRO (Method Resolution Order)
print(f"Hierarquia de Resolução MRO (ProcessadorPIX):")
for i, cls in enumerate(ProcessadorPIX.mro(), start=1):
print(f" {i}. {cls.__name__}")
print("-" * 80)
gateways: list[GatewayPagamento] = [
ProcessadorPIX(),
ProcessadorCartaoCredito(parcelas=1),
ProcessadorCartaoCredito(parcelas=3),
]
requisicao_valor = Decimal("1500.00")
metadados_amostra = {
"chave_pix": "financeiro@acme.com",
"token_cartao": "tok_visa_live_9921",
"cvv_validado": "true"
}
for gw in gateways:
recibo = gw.processar_transacao("OP-8821", requisicao_valor, metadados_amostra)
print(f" Canal : {recibo.canal}")
print(f" Valor Solicitado: R$ {recibo.valor_bruto:>10.2f}")
print(f" Tarifa Retida : R$ {recibo.tarifa_processamento:>10.2f}")
print(f" Líquido Repasse : R$ {recibo.valor_liquido:>10.2f}")
print(f" Status Operação : [{recibo.mensagem_status}]")
print("-" * 80)