🧬 CAPÍTULO 13: HERANÇA, POLIMORFISMO E ASSOCIAÇÕES
🎯 1. Objetivos de Aprendizagem & Competências
Estimativa de Dedicação: 2 horas de estudo autoguiado.
Ao final deste capítulo, você será capaz de:
- 🔹 Diferenciar e aplicar os 4 relacionamentos essenciais da UML: Associação Simples, Agregação (losango vazio), Composição (losango preenchido) e Generalização/Herança (triângulo vazio).
- 🔹 Distinguir Agregação (relação fraca 'tem-um', ciclo de vida independente) de Composição (relação forte 'parte-todo', ciclo de vida dependente e exclusão em cascata).
- 🔹 Aplicar Polimorfismo e Classes Abstratas (
abc.ABC) para garantir desacoplamento e extensibilidade. - 🔹 Implementar relacionamentos no SQLAlchemy 2.0 com
relationship()ecascade="all, delete-orphan".
🏢 2. Cenário Corporativo & Estudo de Caso (TecProExpress)
Na TecProExpress, a plataforma de e-commerce e faturamento processa pedidos compostos por múltiplos itens. Se um Pedido for cancelado ou excluído do banco de dados, todos os seus ItensPedido associados devem ser automaticamente eliminados (Composição). No entanto, o Produto do catálogo continua existindo para outras vendas (Agregação).
O Desafio: Como Arquiteto de Software, você deve modelar as relações entre as classes com as cardinalidades corretas, garantindo que o ciclo de vida dos objetos reflita as regras de negócio e a integridade referencial do banco de dados.
🧠 3. Fundamentação Teórica & Modelos Visuais
3.1. Panorama dos Relacionamentos entre Classes na UML
classDiagram
class Pedido {
+int idPedido
+date dataEmissao
+calcularTotal() Decimal
}
class ItemPedido {
+int quantidade
+Decimal precoUnitario
+subtotal() Decimal
}
class Produto {
+int idProduto
+string nome
+Decimal preco
}
class Cliente {
+int idCliente
+string nome
}
Cliente "1" --> "0..*" Pedido : Associação
Pedido "1" *-- "1..*" ItemPedido : Composição (Todo-Parte Forte)
ItemPedido "0..*" o-- "1" Produto : Agregação (Parte Fraca)
3.2. Comparativo: Agregação vs. Composição vs. Herança
| Relacionamento | Símbolo UML | Ciclo de Vida | Exemplo Prático |
|---|---|---|---|
| Associação | Seta Simples --> | Independente; uma classe utiliza métodos ou dados de outra. | Motorista conduz Caminhão. |
| Agregação | Losango Vazio o-- | Fraco ('tem-um'); a parte pode existir sem o todo. | Departamento agrega Professores. |
| Composição | Losango Cheio *-- | Forte ('parte-todo'); a parte morre junto com o todo. | NotaFiscal compõe ItensNotaFiscal. |
| Herança / Generalização | Triângulo Vazio `< | --` | Compartilhamento de atributos e métodos da superclasse ('é-um'). |
💻 4. Aplicação Prática & Código Executável (Python 3.11+)
📋 Pré-requisitos e Instalação
Este exemplo utiliza os módulos padrão abc, decimal e dataclasses, sem necessidade de pacotes externos:
python --version # Requer Python 3.11 ou superior
💻 Código Completo e Autocontido (modelo_pedido_composicao.py)
Implementação de Composição Forte e Polimorfismo de Estratégia de Desconto em Python 3.11+:
"""
Módulo: modelo_pedido_composicao.py
Domínio: Composição forte e polimorfismo de regras de frete e desconto.
"""
from abc import ABC, abstractmethod
from decimal import Decimal
from dataclasses import dataclass
# --- POLIMORFISMO DE ESTRATÉGIA DE DESCONTO ---
class RegraDesconto(ABC):
@abstractmethod
def calcular_desconto(self, valor_bruto: Decimal) -> Decimal:
pass
class DescontoClientePadrao(RegraDesconto):
def calcular_desconto(self, valor_bruto: Decimal) -> Decimal:
return Decimal("0.00")
class DescontoClienteVIP(RegraDesconto):
def calcular_desconto(self, valor_bruto: Decimal) -> Decimal:
return valor_bruto * Decimal("0.10") # 10% OFF
# --- COMPOSIÇÃO: Pedido e ItemPedido ---
@dataclass
class ItemPedido:
descricao: str
quantidade: int
preco_unitario: Decimal
def subtotal(self) -> Decimal:
return self.quantidade * self.preco_unitario
class Pedido:
def __init__(self, id_pedido: int, estrategia_desconto: RegraDesconto):
self.id_pedido = id_pedido
self.estrategia_desconto = estrategia_desconto
self.itens: list[ItemPedido] = [] # Composição: itens pertencem ao ciclo deste pedido
def adicionar_item(self, descricao: str, quantidade: int, preco: Decimal):
self.itens.append(ItemPedido(descricao, quantidade, preco))
def calcular_total_bruto(self) -> Decimal:
return sum((item.subtotal() for item in self.itens), Decimal("0.00"))
def calcular_total_liquido(self) -> Decimal:
bruto = self.calcular_total_bruto()
desconto = self.estrategia_desconto.calcular_desconto(bruto)
return bruto - desconto
if __name__ == "__main__":
print("--- Simulação de Pedidos com Composição e Polimorfismo ---")
# Pedido 1: Cliente Padrão (Sem Desconto)
pedido_padrao = Pedido(1001, DescontoClientePadrao())
pedido_padrao.adicionar_item("Teclado Mecânico", 1, Decimal("350.00"))
print(f"📦 Pedido #{pedido_padrao.id_pedido} (Padrão):")
print(f" Bruto: R$ {pedido_padrao.calcular_total_bruto():.2f} | Líquido: R$ {pedido_padrao.calcular_total_liquido():.2f}")
# Pedido 2: Cliente VIP (10% OFF)
pedido_vip = Pedido(1002, DescontoClienteVIP())
pedido_vip.adicionar_item("Monitor Dell 27", 2, Decimal("1200.00"))
pedido_vip.adicionar_item("Teclado Mecânico", 1, Decimal("350.00"))
print(f"🌟 Pedido #{pedido_vip.id_pedido} (VIP 10% OFF):")
print(f" Bruto: R$ {pedido_vip.calcular_total_bruto():.2f} | Líquido: R$ {pedido_vip.calcular_total_liquido():.2f}")
🚀 Como Executar
Execute o script diretamente no terminal:
python modelo_pedido_composicao.py
🖥️ Saída Esperada no Terminal
--- Simulação de Pedidos com Composição e Polimorfismo ---
📦 Pedido #1001 (Padrão):
Bruto: R$ 350.00 | Líquido: R$ 350.00
🌟 Pedido #1002 (VIP 10% OFF):
Bruto: R$ 2750.00 | Líquido: R$ 2475.00
💡 5. Checkpoint de Engenharia & Boas Práticas
- Prefira Composição à Herança (Gang of Four): A herança cria acoplamento rígido entre superclasse e subclasse. Sempre que possível, monte comportamentos combinando objetos menores através de composição e interfaces polimórficas.
- Anti-Pattern Cascading Delete Acidental: Em relacionamentos de Agregação, nunca marque
cascade="all, delete-orphan", pois isso apagará entidades compartilhadas acidentalmente.
🔗 6. Conexão com os Projetos Integradores
| Projeto Integrador | Como o conceito deste capítulo é aplicado no PI |
|---|---|
| PI-04: ShopFlow | Composição Pedido ➔ ItemPedido com exclusão em cascata no SQLAlchemy ORM. |
| PI-08: CattleFlow | Agregação entre PastoPiquete e AnimalBovino (o animal é rotacionado de pasto sem ser excluído). |
🧪 7. Quiz de Fixação e Autoavaliação (Formative Assessment)
🧪 Quiz de Autoavaliação — Capítulo 13
🧪 Quiz de Autoavaliação — Capítulo 13
1. Qual é a principal diferença estrutural entre 'Agregação' e 'Composição' na UML?
- A) Agregação usa losango preto e Composição usa triângulo.
- B) Na Composição, a parte possui dependência existencial do todo (se o todo for destruído, as partes deixam de existir); na Agregação, as partes podem existir de forma independente do todo.
- C) Na Agregação, a parte não pode pertencer a nenhuma outra classe.
- D) Não há diferença prática; são termos intercambiáveis na UML 2.5.
💡 Ver Resposta e Justificativa
Resposta Correta: B
Justificativa: A Composição representa um vínculo 'todo-parte' forte com ciclo de vida coincidente (ex: Nota Fiscal e seus Itens). A Agregação é um vínculo fraco onde as partes sobrevivem à destruição do objeto agregador (ex: Time e Jogadores).
2. No diagrama de classes da UML, o símbolo gráfico do relacionamento de 'Composição' é:
- A) Uma linha pontilhada com seta aberta.
- B) Um losango preenchido (losango preto/sólido) no lado do objeto 'Todo'.
- C) Um triângulo vazio no lado da superclasse.
- D) Um círculo com uma cruz dentro.
💡 Ver Resposta e Justificativa
Resposta Correta: B
Justificativa: O losango sólido (preenchido) indica Composição forte no lado da classe que atua como proprietária do ciclo de vida das partes.
3. O princípio da POO 'Polimorfismo' permite:
- A) Gravar dados em arquivos texto sem formatação.
- B) Tratar objetos de diferentes classes derivadas através de uma mesma interface comum, executando comportamentos específicos em tempo de execução.
- C) Impedir o uso de funções assíncronas.
- D) Criar tabelas sem chaves primárias.
💡 Ver Resposta e Justificativa
Resposta Correta: B
Justificativa: O polimorfismo possibilita invocar o mesmo método em objetos de diferentes tipos, com cada objeto respondendo de acordo com sua própria implementação especializada.
🛠️ 8. Ponte para a Ação: Laboratório Prático
Coloque esta teoria em prática executando o roteiro de laboratório autoguiado:
👉 ATIVIDADE 07: DIAGRAMA DE CLASSES (UML)
📌 9. Resumo Executivo & Key Takeaways
- Associação: Relação genérica de conhecimento entre duas classes.
- Agregação (Losango Vazio): Vínculo fraco; as partes continuam existindo de forma independente.
- Composição (Losango Cheio): Vínculo forte de posse existencial; exclusão em cascata obrigatória.
- Polimorfismo: Desacoplamento através de classes base abstratas (
abc.ABC), permitindo trocar algoritmos sem quebrar os clientes.