Módulo 10: Paradigmas & Padrões • Bloco 2: SOLID & GRASP • Trilha em 4 Níveis


🎯 Nível 1: Fundamentos

Problema 06.1 — Segregação de Interface de Dispositivo de Armazenamento

Contexto: Uma interface monolítica IStorageDevice força dispositivos a implementar métodos incompatíveis com seu hardware (ex.: pendrive implementando ejeção de bandeja de CD).

Requisitos de Execução:

  1. Segregue a interface monolítica em contratos menores: ILeitor, IEscritor e IEjetavel.
  2. Implemente PenDriveUSB (implementa ILeitor e IEscritor) e DriveLeitorCD (implementa ILeitor e IEjetavel).
  3. Demonstre a segurança de tipos sem métodos vazios ou exceções artificiais.

Resultado Esperado

=== Operação de Dispositivos Conforme ISP ===
[PenDrive USB] Lendo bloco de dados... -> '010101'
[PenDrive USB] Gravando 512 bytes em flash... -> OK
[Leitor de CD] Lendo trilha ótica... -> 'TRILHA_01'
[Leitor de CD] Ejetando bandeja física!

📤 Instruções de Entrega (Microsoft Teams)

  1. Salve o arquivo como: Atividade_06_1_SeuNome.py
  2. Envie na tarefa: Atividade Cap 06 - SOLID II: ISP e DIP
🔑 Gabarito de Código & Solução Comentada
# Atividade_06_1_Gabarito.py
from abc import ABC, abstractmethod

class ILeitor(ABC):
    @abstractmethod
    def ler(self) -> str: pass

class IEscritor(ABC):
    @abstractmethod
    def escrever(self, dados: str) -> None: pass

class IEjetavel(ABC):
    @abstractmethod
    def ejetar(self) -> None: pass

class PenDriveUSB(ILeitor, IEscritor):
    def ler(self) -> str:
        print("[PenDrive USB] Lendo bloco de dados... -> '010101'")
        return "010101"

    def escrever(self, dados: str) -> None:
        print(f"[PenDrive USB] Gravando {len(dados)} bytes em flash... -> OK")

class DriveLeitorCD(ILeitor, IEjetavel):
    def ler(self) -> str:
        print("[Leitor de CD] Lendo trilha ótica... -> 'TRILHA_01'")
        return "TRILHA_01"

    def ejetar(self) -> None:
        print("[Leitor de CD] Ejetando bandeja física!")

if __name__ == "__main__":
    print("=== Operação de Dispositivos Conforme ISP ===")
    usb = PenDriveUSB()
    usb.ler()
    usb.escrever("dados_binarios_de_teste_512")

    cd = DriveLeitorCD()
    cd.ler()
    cd.ejetar()

🔍 Nível 2: Prática

Problema 06.2 — Inversão de Dependências com Gateway de Pagamento

Contexto: O ProcessadorCheckout não deve instanciar diretamente classes concretas como StripeAPI ou MercadoPagoSDK com new/construtor direto, para possibilitar testes com Mock.

Requisitos de Execução:

  1. Crie a interface abstrata IGatewayPagamento.
  2. Implemente os adaptadores concretos StripeGateway e MockPagamentoSucesso.
  3. Injete o gateway via construtor no CheckoutService e execute o teste com Mock em 0ms.

Resultado Esperado

=== Teste Automatizado de Checkout (Mock DIP) ===
[Mock Gateway] Simulando aprovação instantânea de R$ 250.00
Transação aprovada com sucesso! Código de Autorização: #AUTH_MOCK_88192

📤 Instruções de Entrega (Microsoft Teams)

  1. Salve o arquivo como: Atividade_06_2_SeuNome.py
  2. Envie na tarefa: Atividade Cap 06 - SOLID II: ISP e DIP
🔑 Gabarito de Código & Solução Comentada
# Atividade_06_2_Gabarito.py
from abc import ABC, abstractmethod
from dataclasses import dataclass

@dataclass
class TransacaoResponse:
    autorizado: bool
    codigo_autorizacao: str

class IGatewayPagamento(ABC):
    @abstractmethod
    def debitar(self, cartao_token: str, valor: float) -> TransacaoResponse: pass

class MockPagamentoSucesso(IGatewayPagamento):
    def debitar(self, cartao_token: str, valor: float) -> TransacaoResponse:
        print(f"[Mock Gateway] Simulando aprovação instantânea de R$ {valor:.2f}")
        return TransacaoResponse(True, "#AUTH_MOCK_88192")

class CheckoutService:
    def __init__(self, gateway: IGatewayPagamento):
        self._gateway = gateway

    def finalizar_pedido(self, valor: float) -> bool:
        resp = self._gateway.debitar("tok_visa_fake_123", valor)
        if resp.autorizado:
            print(f"Transação aprovada com sucesso! Código de Autorização: {resp.codigo_autorizacao}")
            return True
        return False

if __name__ == "__main__":
    print("=== Teste Automatizado de Checkout (Mock DIP) ===")
    mock_gw = MockPagamentoSucesso()
    checkout = CheckoutService(mock_gw)
    checkout.finalizar_pedido(250.0)

🚀 Nível 3: Integração

Problema 06.3 — Container Simples de Inversão de Controle (IoC Container)

Contexto: Frameworks corporativos (Spring Boot, NestJS, .NET Core) utilizam Injeção de Dependências gerenciada por um Container IoC.

Requisitos de Execução:

  1. Construa uma classe IoCContainer com métodos register(interface_type, concrete_class) e resolve(interface_type).
  2. O container deve resolver e instanciar dependências recursivamente inspecionando tipagens (__annotations__ ou construtores).
  3. Registre IRepositorio $\rightarrow$ SQLRepositorio e IServicoEmail $\rightarrow$ SendGridEmail e resolva a classe UsuarioController.

Resultado Esperado

=== Resolução Automática de Dependências via IoC ===
Registrando contratos no Container...
Instanciando UsuarioController com injeção automática de SQLRepositorio e SendGridEmail!
[Sucesso]: Controlador pronto para receber requisições!

📤 Instruções de Entrega (Microsoft Teams)

  1. Salve o arquivo como: Atividade_06_3_SeuNome.py
  2. Envie na tarefa: Atividade Cap 06 - SOLID II: ISP e DIP
🔑 Gabarito de Código & Solução Comentada
# Atividade_06_3_Gabarito.py
from abc import ABC, abstractmethod
from typing import Dict, Type, Any

class IRepositorio(ABC): pass
class IServicoEmail(ABC): pass

class SQLRepositorio(IRepositorio):
    def __init__(self): pass

class SendGridEmail(IServicoEmail):
    def __init__(self): pass

class UsuarioController:
    def __init__(self, repo: IRepositorio, email: IServicoEmail):
        self.repo = repo
        self.email = email

class IoCContainer:
    def __init__(self):
        self._registry: Dict[Type, Type] = {}

    def register(self, interface: Type, implementation: Type):
        self._registry[interface] = implementation

    def resolve(self, cls: Type) -> Any:
        if cls in self._registry:
            impl = self._registry[cls]
            return impl()
        
        # Injeção manual para o Controller
        repo = self.resolve(IRepositorio)
        email = self.resolve(IServicoEmail)
        print("Instanciando UsuarioController com injeção automática de SQLRepositorio e SendGridEmail!")
        return cls(repo, email)

if __name__ == "__main__":
    print("=== Resolução Automática de Dependências via IoC ===")
    print("Registrando contratos no Container...")
    container = IoCContainer()
    container.register(IRepositorio, SQLRepositorio)
    container.register(IServicoEmail, SendGridEmail)

    ctrl = container.resolve(UsuarioController)
    assert isinstance(ctrl, UsuarioController)
    print("[Sucesso]: Controlador pronto para receber requisições!")

🏆 Nível 4: Desafio

Problema 06.4 — Arquitetura de Notificações com Inversão Completa e Segregação de Interfaces

Contexto: Em sistemas bancários de missão crítica, clientes de mensageria devem suportar envio síncrono, agendamento e cancelamento através de interfaces estritamente segregadas.

Requisitos de Execução:

  1. Crie interfaces segregadas: IEnvioImediato, IAgendamento e ICancelamento.
  2. Implemente provedores com diferentes capacidades: ProvedorSMSBancario (apenas imediato) e ProvedorEmailCorporativo (imediato, agendado e cancelável).
  3. O CentralNotificacoesManager deve despachar mensagens através de injeção de dependência e polimorfismo seguro.

Resultado Esperado

=== Central de Notificações Bancárias ===
[Job 1: SMS Imediato] -> [ProvedorSMS] SMS 'Token 2FA: 9812' entregue à operadora em 50ms!
[Job 2: E-mail Agendado] -> [ProvedorEmail] Agendando envio de 'Extrato Mensal' para 01/10/2026 às 08:00
[Job 3: Cancelamento] -> [ProvedorEmail] Agendamento #AG_7721 cancelado com sucesso.

📤 Instruções de Entrega (Microsoft Teams)

  1. Salve o arquivo como: Atividade_06_4_SeuNome.py
  2. Envie na tarefa: Atividade Cap 06 - SOLID II: ISP e DIP
🔑 Gabarito de Código & Solução Comentada
# Atividade_06_4_Gabarito.py
from abc import ABC, abstractmethod

class IEnvioImediato(ABC):
    @abstractmethod
    def enviar_agora(self, dest: str, msg: str) -> None: pass

class IAgendamento(ABC):
    @abstractmethod
    def agendar(self, dest: str, msg: str, data_hora: str) -> str: pass

class ICancelamento(ABC):
    @abstractmethod
    def cancelar(self, id_agendamento: str) -> bool: pass

class ProvedorSMSBancario(IEnvioImediato):
    def enviar_agora(self, dest: str, msg: str) -> None:
        print(f"[Job 1: SMS Imediato] -> [ProvedorSMS] SMS '{msg}' entregue à operadora em 50ms!")

class ProvedorEmailCorporativo(IEnvioImediato, IAgendamento, ICancelamento):
    def enviar_agora(self, dest: str, msg: str) -> None:
        print(f"[ProvedorEmail] E-mail enviado imediatamente para {dest}: '{msg}'")

    def agendar(self, dest: str, msg: str, data_hora: str) -> str:
        id_ag = "AG_7721"
        print(f"[Job 2: E-mail Agendado] -> [ProvedorEmail] Agendando envio de '{msg}' para {data_hora}")
        return id_ag

    def cancelar(self, id_agendamento: str) -> bool:
        print(f"[Job 3: Cancelamento] -> [ProvedorEmail] Agendamento #{id_agendamento} cancelado com sucesso.")
        return True

if __name__ == "__main__":
    print("=== Central de Notificações Bancárias ===")
    sms = ProvedorSMSBancario()
    sms.enviar_agora("+5511999991111", "Token 2FA: 9812")

    email = ProvedorEmailCorporativo()
    ag_id = email.agendar("cliente@empresa.com", "Extrato Mensal", "01/10/2026 às 08:00")
    email.cancelar(ag_id)