Módulo 10: Paradigmas & Padrões • Bloco 2: SOLID & GRASP • Demonstrações Práticas

🏛️ Padrões GRASP Avançados na Prática: Demonstrações funcionais dos quatro padrões avançados de Craig Larman. No Exemplo 1, construímos uma arquitetura de pagamentos multimercado utilizando Polymorphism e Protected Variations com suporte a failover dinâmico. No Exemplo 2, aplicamos Pure Fabrication e Indirection para implementar um pipeline corporativo de auditoria de segurança assíncrono.


1. Gateway de Pagamento Multiprovedor: Polymorphism & Protected Variations

Neste exemplo, protegemos o núcleo de checkout contra a instabilidade e volatilidade de APIs de adquirentes terceiros. O cliente depende de uma interface estável (Protected Variations), e as diferentes operadoras respondem via despacho polimórfico (Polymorphism):

# grasp_pv_poly_pagamentos.py
from abc import ABC, abstractmethod
from typing import Dict, Any, List
from dataclasses import dataclass
import time

@dataclass(frozen=True)
class SolicitacaoCobranca:
    id_pedido: str
    cliente_documento: str
    valor: float
    moeda: str = "BRL"

@dataclass(frozen=True)
class RespostaCobranca:
    sucesso: bool
    codigo_autorizacao: str
    operadora: str
    mensagem: str

# 1. Protected Variations: Interface estável que blinda o negócio contra mudanças
class IAdquirentePagamento(ABC):
    @abstractmethod
    def autorizar(self, solicitacao: SolicitacaoCobranca) -> RespostaCobranca:
        pass

    @abstractmethod
    def obter_nome_provedor(self) -> str:
        pass

# 2. Polymorphism: Cada operadora encapsula suas particularidades de comunicação
class StripeGatewayAdapter(IAdquirentePagamento):
    def autorizar(self, solicitacao: SolicitacaoCobranca) -> RespostaCobranca:
        # Simula chamada à API REST do Stripe
        print(f"  🌐 [Stripe REST API] Processando cobrança de R$ {solicitacao.valor:.2f}...")
        return RespostaCobranca(
            sucesso=True,
            codigo_autorizacao="ch_stripe_9921_ok",
            operadora="Stripe Global",
            mensagem="Transação aprovada com sucesso."
        )

    def obter_nome_provedor(self) -> str:
        return "Stripe v3"

class MercadoPagoAdapter(IAdquirentePagamento):
    def autorizar(self, solicitacao: SolicitacaoCobranca) -> RespostaCobranca:
        print(f"  🌐 [MercadoPago SDK] Autorizando débito de R$ {solicitacao.valor:.2f}...")
        return RespostaCobranca(
            sucesso=True,
            codigo_autorizacao="mp_auth_883344",
            operadora="MercadoPago Latam",
            mensagem="Pagamento liquidado instantaneamente."
        )

    def obter_nome_provedor(self) -> str:
        return "MercadoPago API"

class PixBancoCentralAdapter(IAdquirentePagamento):
    def autorizar(self, solicitacao: SolicitacaoCobranca) -> RespostaCobranca:
        print(f"  ⚡ [SPI / BACEN] Gerando payload PIX e validando chave...")
        return RespostaCobranca(
            sucesso=True,
            codigo_autorizacao="E0003816620260928_PIX",
            operadora="Bacen SPI",
            mensagem="Transferência PIX confirmada em 180ms."
        )

    def obter_nome_provedor(self) -> str:
        return "PIX Instantâneo"

# 3. Núcleo de Negócio com Mecanismo de Failover (Blindagem Completa)
class MotorLiquidacaoVendas:
    """Consome a interface estável sem saber quais operadoras existem fisicamente."""
    def __init__(self, adquirentes: List[IAdquirentePagamento]):
        if not adquirentes:
            raise ValueError("O motor de liquidação requer ao menos um adquirente configurado.")
        self.adquirentes = adquirentes

    def liquidar(self, solicitacao: SolicitacaoCobranca) -> RespostaCobranca:
        print(f"\n[Motor de Liquidação] Iniciando cobrança do pedido #{solicitacao.id_pedido}")
        
        # Tentativa sequencial com tolerância a falhas (Protected Variations)
        for adquirente in self.adquirentes:
            try:
                resposta = adquirente.autorizar(solicitacao)
                if resposta.sucesso:
                    print(f"  ✅ Pagamento autorizado via [{adquirente.obter_nome_provedor()}]. Código: {resposta.codigo_autorizacao}")
                    return resposta
            except Exception as erro:
                print(f"  ⚠️ Provedor [{adquirente.obter_nome_provedor()}] falhou: {erro}. Alternando para fallback...")
        
        raise RuntimeError("Todas as operadoras de pagamento falharam. Operação abortada.")

# Demonstração Prática
if __name__ == "__main__":
    cobranca = SolicitacaoCobranca("PED-2026-9901", "123.456.789-00", 750.00)

    # Configuração de rota com fallback em tempo de execução
    adquirentes_ativos = [
        PixBancoCentralAdapter(),
        StripeGatewayAdapter(),
        MercadoPagoAdapter()
    ]

    motor = MotorLiquidacaoVendas(adquirentes_ativos)
    resultado = motor.liquidar(cobranca)
    print(f"Status Final: {resultado.mensagem}")

2. Auditoria e Telemetria: Pure Fabrication & Indirection

Neste exemplo, aplicamos Pure Fabrication para conceber classes técnicas artificiais (sem lastro no mundo real dos negócios) e Indirection para interpor um despachante intermediário, isolando totalmente as entidades financeiras:

# grasp_pure_fab_indirection.py
from abc import ABC, abstractmethod
from typing import List, Dict, Any
from datetime import datetime

# Entidade Conceitual do Domínio (Mundo Real)
class TransferenciaPix:
    def __init__(self, txid: str, pagador: str, recebedor: str, valor: float):
        self.txid = txid
        self.pagador = pagador
        self.recebedor = recebedor
        self.valor = valor
        self.status = "PENDENTE"

    def efetivar(self):
        self.status = "CONCLUIDA"

# 1. Pure Fabrication: Interfaces e classes concebidas puramente para o design
class ICanalAuditoria(ABC):
    @abstractmethod
    def registrar_evento(self, evento: Dict[str, Any]):
        pass

class LogArquivoAuditoria(ICanalAuditoria):
    def registrar_evento(self, evento: Dict[str, Any]):
        print(f"  📄 [File Sink] [AUDIT_SEC] {evento['tipo']} | TX: {evento['txid']} | TS: {evento['timestamp']}")

class TelemetriaCloudWatch(ICanalAuditoria):
    def registrar_evento(self, evento: Dict[str, Any]):
        print(f"  ☁️ [CloudWatch Metrics] Métrica de negócio 'PIX_SETTLED' incrementada (+1). Valor: R$ {evento['valor']:.2f}")

# 2. Indirection: Mediador intermediário que evita acoplamento direto entre domínio e canais
class DespachanteAuditoriaIndireta:
    """Pure Fabrication + Indirection: Desacopla o domínio das ferramentas de monitoramento."""
    def __init__(self):
        self._canais: List[ICanalAuditoria] = []

    def adicionar_canal(self, canal: ICanalAuditoria):
        self._canais.append(canal)

    def despachar(self, transferencia: TransferenciaPix, tipo_evento: str):
        payload = {
            "txid": transferencia.txid,
            "pagador": transferencia.pagador,
            "recebedor": transferencia.recebedor,
            "valor": transferencia.valor,
            "tipo": tipo_evento,
            "timestamp": datetime.utcnow().isoformat() + "Z"
        }
        for canal in self._canais:
            canal.registrar_evento(payload)

# 3. Serviço de Aplicação Orquestrador
class ServicoTransferenciaBancaria:
    def __init__(self, auditoria_mediator: DespachanteAuditoriaIndireta):
        self.auditoria = auditoria_mediator

    def realizar_pix(self, txid: str, pagador: str, recebedor: str, valor: float) -> TransferenciaPix:
        pix = TransferenciaPix(txid, pagador, recebedor, valor)
        
        # Notificação mediada via Indireção
        self.auditoria.despachar(pix, "PIX_INICIADO")
        pix.efetivar()
        self.auditoria.despachar(pix, "PIX_EFETIVADO")
        return pix

# Execução Prática
if __name__ == "__main__":
    print("\n" + "=" * 65)
    print("🏭 DEMONSTRAÇÃO: PURE FABRICATION & INDIRECTION EM AUDITORIA")
    print("=" * 65)

    # Configuração dos intermediários
    mediador_auditoria = DespachanteAuditoriaIndireta()
    mediador_auditoria.adicionar_canal(LogArquivoAuditoria())
    mediador_auditoria.adicionar_canal(TelemetriaCloudWatch())

    servico = ServicoTransferenciaBancaria(mediador_auditoria)
    pix_resultado = servico.realizar_pix("TX-88201-BACEN", "João Silva", "Empresa Alpha Ltda", 1850.00)
    print(f"\nStatus Final da Transferência: {pix_resultado.status}")

Saída Esperada dos Scripts:

[Motor de Liquidação] Iniciando cobrança do pedido #PED-2026-9901
  ⚡ [SPI / BACEN] Gerando payload PIX e validando chave...
  ✅ Pagamento autorizado via [PIX Instantâneo]. Código: E0003816620260928_PIX
Status Final: Transferência PIX confirmada em 180ms.

=================================================================
🏭 DEMONSTRAÇÃO: PURE FABRICATION & INDIRECTION EM AUDITORIA
=================================================================
  📄 [File Sink] [AUDIT_SEC] PIX_INICIADO | TX: TX-88201-BACEN | TS: 2026-09-28T14:40:00.000000Z
  ☁️ [CloudWatch Metrics] Métrica de negócio 'PIX_SETTLED' incrementada (+1). Valor: R$ 1850.00
  📄 [File Sink] [AUDIT_SEC] PIX_EFETIVADO | TX: TX-88201-BACEN | TS: 2026-09-28T14:40:00.000000Z
  ☁️ [CloudWatch Metrics] Métrica de negócio 'PIX_SETTLED' incrementada (+1). Valor: R$ 1850.00

Status Final da Transferência: CONCLUIDA