💻 Exemplos: SOLID II: ISP e DIP / IoC
Módulo 10: Paradigmas & Padrões • Bloco 2: SOLID & GRASP • Demonstrações Práticas
🏛️ Desacoplamento e Injeção de Dependências na Prática: Demonstrações funcionais dos princípios ISP e DIP. No Exemplo 1, aplicamos a Segregação de Interfaces em um sistema de processamento fiscal e contábil. No Exemplo 2, construímos um mini-container IoC (Inversion of Control Container com Autowiring) em Python que resolve automaticamente o grafo de dependências via introspecção de tipos.
1. Segregação de Interfaces (ISP) em Pipeline Documental
Neste exemplo, eliminamos uma interface volumosa (Fat Interface) decompondo-a em interfaces de papel (Role Interfaces) coesas. Cada cliente consome apenas o subconjunto de métodos estritamente necessários à sua operação:
# solid_isp_documentos.py
from abc import ABC, abstractmethod
from typing import List
# 1. Interfaces Granulares de Papel (Role Interfaces - 100% ISP Conforme)
class ILeitorDocumento(ABC):
@abstractmethod
def ler_conteudo(self, caminho_arquivo: str) -> str:
pass
class IGeradorPDF(ABC):
@abstractmethod
def exportar_pdf(self, conteudo: str, caminho_destino: str) -> bool:
pass
class IAssinadorDigital(ABC):
@abstractmethod
def assinar_criptograficamente(self, payload: str, certificado_pem: str) -> str:
pass
class ITransmissorSEFAZ(ABC):
@abstractmethod
def transmitir_lote(self, xml_assinado: str) -> str:
pass
# 2. Implementações Concretas com Habilidades Específicas
class DispositivoVisualizadorSimples(ILeitorDocumento):
"""Apenas lê documentos para exibição na tela. Não gera PDF nem assina nada."""
def ler_conteudo(self, caminho_arquivo: str) -> str:
print(f" 📖 [Visualizador] Carregando bytes de: {caminho_arquivo}")
return "<xml><fatura valor='1500.00' /></xml>"
class ServicoEmissaoFiscalAvancado(ILeitorDocumento, IAssinadorDigital, ITransmissorSEFAZ):
"""Serviço corporativo que orquestra leitura, assinatura com certificado A1 e transmissão."""
def ler_conteudo(self, caminho_arquivo: str) -> str:
print(f" 📂 [Fiscal] Lendo XML de fatura: {caminho_arquivo}")
return "<xml><nota id='4501' total='9800.00' /></xml>"
def assinar_criptograficamente(self, payload: str, certificado_pem: str) -> str:
print(f" 🔐 [Criptografia] Assinando payload com certificado RSA SHA-256...")
return f"{payload}<!-- ASSINATURA_DIGITAL_RSA_VALIDA -->"
def transmitir_lote(self, xml_assinado: str) -> str:
print(f" 📡 [SEFAZ] Transmitindo lote SOAP via mTLS para a Receita Federal...")
return "RECIBO_SEFAZ_AUTORIZADO_2026_9988"
# 3. Consumidores Específicos: Acoplados APENAS ao que utilizam
def rotina_auditoria_leitura(leitor: ILeitorDocumento, caminho: str):
print("\n[Audit Routine] Verificando integridade de arquivo:")
conteudo = leitor.ler_conteudo(caminho)
print(f" Tamanho do conteúdo lido: {len(conteudo)} caracteres.")
def rotina_transmissao_governamental(assinador: IAssinadorDigital, transmissor: ITransmissorSEFAZ, xml: str):
print("\n[Gov Transmit Routine] Executando protocolo oficial:")
xml_assinado = assinador.assinar_criptograficamente(xml, "cert_a1.pem")
protocolo = transmissor.transmitir_lote(xml_assinado)
print(f" ✅ Transmissão homologada com protocolo: {protocolo}")
# Demonstração Prática
if __name__ == "__main__":
visualizador = DispositivoVisualizadorSimples()
servico_fiscal = ServicoEmissaoFiscalAvancado()
print("=" * 65)
print("✂️ DEMONSTRAÇÃO DO PRINCÍPIO DE SEGREGAÇÃO DE INTERFACES (ISP)")
print("=" * 65)
# O visualizador simples é aceito pela rotina que só exige leitura
rotina_auditoria_leitura(visualizador, "/tmp/fatura_01.xml")
# O serviço fiscal atende a ambos os contratos sem poluição de métodos
rotina_auditoria_leitura(servico_fiscal, "/var/notas/nfe_4501.xml")
rotina_transmissao_governamental(servico_fiscal, servico_fiscal, "<nfe valor='9800'/>")
2. Container IoC com Resolução Automática de Dependências (Autowiring)
Neste exemplo, implementamos do zero um container de Inversão de Controle (IoC Container) que inspeciona assinaturas de tipo e resolve todo o grafo de dependências via injeção por construtor:
# solid_dip_ioc_container.py
import inspect
from abc import ABC, abstractmethod
from typing import Dict, Type, Any, get_type_hints
# 1. Abstrações de Domínio (DIP - Núcleo de Alto Nível)
class ILogger(ABC):
@abstractmethod
def log(self, mensagem: str): pass
class IGatewayPagamento(ABC):
@abstractmethod
def cobrar(self, cliente: str, valor: float) -> bool: pass
class INotificadorSMS(ABC):
@abstractmethod
def notificar(self, telefone: str, texto: str): pass
# 2. Implementações Técnicas de Baixo Nível
class ConsoleLogger(ILogger):
def log(self, mensagem: str):
print(f" 📝 [LOG DE AUDITORIA] {mensagem}")
class StripeGatewayPagamento(IGatewayPagamento):
def __init__(self, logger: ILogger):
self.logger = logger
def cobrar(self, cliente: str, valor: float) -> bool:
self.logger.log(f"Conectando à API REST do Stripe para debitar R$ {valor:.2f} do cliente '{cliente}'...")
return True
class TwilioNotificadorSMS(INotificadorSMS):
def __init__(self, logger: ILogger):
self.logger = logger
def notificar(self, telefone: str, texto: str):
self.logger.log(f"Disparando SMS via Twilio Gateway para {telefone}: '{texto}'")
# 3. Módulo de Alto Nível de Negócio (Checkout)
class CheckoutPedidoService:
"""Depende EXCLUSIVAMENTE de abstrações fornecidas pelo construtor."""
def __init__(self, gateway: IGatewayPagamento, sms: INotificadorSMS, logger: ILogger):
self.gateway = gateway
self.sms = sms
self.logger = logger
def finalizar_compra(self, pedido_id: str, cliente: str, telefone: str, valor: float):
self.logger.log(f"Iniciando checkout do pedido #{pedido_id}")
sucesso = self.gateway.cobrar(cliente, valor)
if sucesso:
self.sms.notificar(telefone, f"Seu pedido #{pedido_id} de R$ {valor:.2f} foi aprovado!")
self.logger.log(f"Pedido #{pedido_id} concluído com êxito total.")
# 4. Mecanismo de IoC Container com Injeção por Autowiring
class IoCContainer:
def __init__(self):
self._servicos: Dict[Type, Any] = {}
self._singletons: Dict[Type, Any] = {}
def registrar_singleton(self, interface: Type, implementacao: Type):
"""Registra uma implementação no escopo Singleton (compartilhada)."""
self._servicos[interface] = (implementacao, "SINGLETON")
def registrar_transient(self, interface: Type, implementacao: Type):
"""Registra uma implementação no escopo Transient (nova instância a cada resolução)."""
self._servicos[interface] = (implementacao, "TRANSIENT")
def resolver(self, tipo_alvo: Type) -> Any:
"""Resolve recursivamente as dependências do construtor inspecionando tipagem."""
if tipo_alvo in self._servicos:
impl_classe, escopo = self._servicos[tipo_alvo]
if escopo == "SINGLETON" and tipo_alvo in self._singletons:
return self._singletons[tipo_alvo]
else:
impl_classe = tipo_alvo
escopo = "TRANSIENT"
# Inspecionar construtor
assinatura = inspect.signature(impl_classe.__init__)
tipos = get_type_hints(impl_classe.__init__)
argumentos = {}
for nome_param, param in assinatura.parameters.items():
if nome_param == "self":
continue
tipo_param = tipos.get(nome_param)
if tipo_param is None:
raise TypeError(f"Não foi possível inferir tipo do parâmetro '{nome_param}' em {impl_classe}")
# Resolução recursiva de dependência
argumentos[nome_param] = self.resolver(tipo_param)
instancia = impl_classe(**argumentos)
if tipo_alvo in self._servicos and self._servicos[tipo_alvo][1] == "SINGLETON":
self._singletons[tipo_alvo] = instancia
return instancia
# 5. Composition Root (Ponto Único de Inicialização)
if __name__ == "__main__":
print("\n" + "=" * 65)
print("🔄 RESOLUÇÃO DE DEPENDÊNCIAS VIA CONTAINER IoC (DIP PLENO)")
print("=" * 65)
container = IoCContainer()
# Amarração de abstrações com classes concretas
container.registrar_singleton(ILogger, ConsoleLogger)
container.registrar_transient(IGatewayPagamento, StripeGatewayPagamento)
container.registrar_transient(INotificadorSMS, TwilioNotificadorSMS)
# O container descobre e monta todo o grafo de objetos automaticamente!
checkout_app = container.resolver(CheckoutPedidoService)
# Execução do fluxo de negócio sem acoplamento técnico
checkout_app.finalizar_compra(
pedido_id="PED-7788",
cliente="Mariana Guimarães",
telefone="+5511988887777",
valor=1450.00
)
Saída Esperada dos Scripts:
=================================================================
✂️ DEMONSTRAÇÃO DO PRINCÍPIO DE SEGREGAÇÃO DE INTERFACES (ISP)
=================================================================
[Audit Routine] Verificando integridade de arquivo:
📖 [Visualizador] Carregando bytes de: /tmp/fatura_01.xml
Tamanho do conteúdo lido: 34 caracteres.
[Audit Routine] Verificando integridade de arquivo:
📂 [Fiscal] Lendo XML de fatura: /var/notas/nfe_4501.xml
Tamanho do conteúdo lido: 42 caracteres.
[Gov Transmit Routine] Executando protocolo oficial:
🔐 [Criptografia] Assinando payload com certificado RSA SHA-256...
📡 [SEFAZ] Transmitindo lote SOAP via mTLS para a Receita Federal...
✅ Transmissão homologada com protocolo: RECIBO_SEFAZ_AUTORIZADO_2026_9988
=================================================================
🔄 RESOLUÇÃO DE DEPENDÊNCIAS VIA CONTAINER IoC (DIP PLENO)
=================================================================
📝 [LOG DE AUDITORIA] Iniciando checkout do pedido #PED-7788
📝 [LOG DE AUDITORIA] Conectando à API REST do Stripe para debitar R$ 1450.00 do cliente 'Mariana Guimarães'...
📝 [LOG DE AUDITORIA] Disparando SMS via Twilio Gateway para +5511988887777: 'Seu pedido #PED-7788 de R$ 1450.00 foi aprovado!'
📝 [LOG DE AUDITORIA] Pedido #PED-7788 concluído com êxito total.