Projeto 07: Refatoração Orientada aos Princípios SOLID 🧱
Escopo do Projeto
Objetivo: Refatorar um código legado monolítico repleto de violações arquiteturais aplicando os cinco princípios SOLID (Single Responsibility, Open-Closed, Liskov Substitution, Interface Segregation e Dependency Inversion).
🎯 1. Contexto & Desafio Prático
Você recebeu uma 'God Class' de faturamento de 500 linhas que conecta no banco, calcula impostos em cascata de ifs, envia e-mails e imprime relatórios. Sua missão é refatorar o sistema aplicando rigorosamente os cinco princípios SOLID.
📋 2. Requisitos Técnicos Obrigatórios
- R1 (Single Responsibility Principle - SRP): Separar a classe monolítica em classes coesas: repositório de dados, motor de cálculo fiscal e serviço de notificação.
- R2 (Open/Closed Principle - OCP): Implementar interface de cálculo tributário permitindo adicionar novos impostos sem modificar classes existentes.
- R3 (Liskov Substitution Principle - LSP): Garantir que todas as subclasses de pagamento possam substituir a classe base sem quebrar o comportamento.
- R4 (Dependency Inversion Principle - DIP): Injetar dependências via construtor utilizando interfaces e abstrações em vez de instanciar classes concretas internamente.
📐 3. Diagrama Conceitual & Arquitetura
graph TD
GodClass["Monólito Violando SOLID (God Class)"] --> Refactor["Refatoração com SOLID"]
Refactor --> SRP["SRP: InvoiceRepository, TaxCalculator, Notifier"]
Refactor --> OCP["OCP: Interface TaxStrategy (Novos impostos sem mudar código)"]
Refactor --> DIP["DIP: Injeção de Dependências por Interfaces"]
style GodClass fill:#ffebee,stroke:#c62828
style Refactor fill:#fff3e0,stroke:#e65100
style SRP fill:#e1f5fe,stroke:#01579b
style OCP fill:#e8f5e9,stroke:#2e7d32
style DIP fill:#f3e5f5,stroke:#7b1fa2 💻 4. Especificação Técnica & Código de Referência
// solid_refactoring.py
from abc import ABC, abstractmethod
# OCP & DIP: Contrato abstrato para impostos
class TaxStrategy(ABC):
@abstractmethod
def calculate(self, amount: float) -> float:
pass
class ICMS(TaxStrategy):
def calculate(self, amount: float) -> float:
return amount * 0.18
# DIP: Serviço depende de abstração de notificação
class NotificationService(ABC):
@abstractmethod
def send(self, recipient: str, message: str) -> None:
pass
class OrderProcessor:
def __init__(self, tax_strategy: TaxStrategy, notifier: NotificationService):
self.tax_strategy = tax_strategy
self.notifier = notifier
def process(self, amount: float, customer_email: str) -> float:
tax = self.tax_strategy.calculate(amount)
total = amount + tax
self.notifier.send(customer_email, f"Total do Pedido: {total}")
return total
📦 5. Critérios de Avaliação e Entrega
- Código refatorado com 100% de desacoplamento comprovado.
- Demonstração da adição de um novo imposto (ex: ISS) sem alterar
OrderProcessor. - Suíte de testes unitários com mocks comprovando o isolamento das dependências.