Aplicando Composição sobre Herança
Início rápido
- Identifique o eixo de variação: variante de dados, algoritmo, comportamento transversal ou restrição de framework.
- Por padrão, prefira composição, a menos que a herança seja explicitamente justificada por substituibilidade e estabilidade.
- Se o conjunto de variantes é fechado e baseado em dados, prefira um tipo ADT/selado em vez de herança aberta.
- Produza um plano de migração concreto com testes, ordem de implantação e pontos de verificação de revisão.
Roteiro de referência (divulgação progressiva)
Leia apenas o arquivo necessário para a tarefa atual:
- Fundamentos e escolha de mecanismo → references/01-foundations-and-decision-making.md
- ADTs, padrões de composição, composição no frontend → references/02-adts-patterns-and-frontend-composition.md
- Migração passo a passo e verificações de revisão de código → references/03-refactoring-and-review-checklist.md
- Métricas de CI, verificações estáticas personalizadas, adoção pela equipe → references/04-metrics-and-adoption.md
Fluxo de trabalho padrão
-
Avalie o modelo atual
- Liste classes base, quantidade de subclasses, profundidade da hierarquia e pontos problemáticos conhecidos.
- Marque cada variação como: variante de dados, estratégia de comportamento ou preocupação de infraestrutura.
-
Escolha o mecanismo (primeiro o padrão)
- Escolha composição para variação de comportamento, troca em tempo de execução ou mudança em múltiplos eixos.
- Escolha tipo ADT/selado para variantes fechadas que carregam dados e exigem tratamento exaustivo.
- Escolha herança apenas quando todas as condições forem verdadeiras: relação é-um real, substituibilidade Liskov-safe e hierarquia estável.
-
Projete a forma alvo
- Defina contratos mínimos de colaboradores; introduza interfaces/protocolos onde volatilidade, múltiplas implementações ou testes independentes os justifiquem.
- Use injeção no construtor para colaboradores obrigatórios.
- Mantenha a profundidade da herança baixa (alvo ≤2 abaixo de bases de framework inevitáveis).
-
Planeje a migração incrementalmente
- Adicione testes de caracterização primeiro.
- Introduza uma costura (interface/fachada) antes de substituir os internos.
- Migre um caminho de subclasse por vez.
- Remova partes mortas da hierarquia somente após verificações de paridade passarem.
-
Valide e coloque barreiras
- Realize revisão orientada por checklist.
- Adicione métricas/verificações de CI para DIT, taxa de sobrescrita e profundidade de decorador.
- Capture isenções explícitas para herança exigida pelo framework.
Padrões inegociáveis
- Prefira composição por padrão.
- Não introduza herança puramente para reuso de código.
- Mantenha as interfaces dos colaboradores estreitas.
- Evite padrões de localizador de serviços; dependências devem ser explícitas.
- Trate pilhas profundas de decoradores (>3) e árvores de herança largas como maus cheiros de design.
Contrato de saída
Quando solicitado a fornecer orientação, retorne estas seções em ordem:
- Decisão: composição, ADT ou herança.
- Por quê: acoplamento, eixo de mudança, necessidades de tempo de execução e implicações de testabilidade.
- Esboço do design: interfaces/tipos alvo e raiz de composição.
- Passos de migração: passos pequenos e reversíveis com pontos de validação.
- Verificações de revisão/CI: itens do checklist e limites mensuráveis.
Casos de borda
- Herança exigida pelo framework: mantenha a herança na fronteira; componha internamente.
- Linguagem carece de açúcar sintático para delegação: use pequenos geradores/modelos auxiliares para encaminhamento.
- Caminhos críticos de desempenho: meça a sobrecarga de despacho antes de adicionar indireção.
- Domínios pequenos e estáveis: herança selada pode ser aceitável quando a exaustividade é necessária.
Exemplo
Entrada: “Temos BaseReport com 12 subclasses e cada novo formato adiciona outra subclasse. O que devemos fazer?”
Saída (formato):
- Decisão: Substituir a hierarquia por composição (Strategy + opcional Decorator).
- Por quê: variação em múltiplos eixos e subclasses com muitas sobrescritas indicam desvio taxonômico.
- Esboço do design: interfaces
ReportRenderer,HeaderPolicy,FooterPolicy,OutputFormattercompostas em umReportService. - Migração: testes de caracterização → extração de estratégia → migração por subclasse → exclusão de subclasses.
- Barreiras: DIT alerta >3, taxa de sobrescrita alerta >0.5, profundidade do decorador alerta >3.