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.ABC com 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 AuditavelMixin demonstrando herança múltipla, chamadas cooperativas via super() 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)