Skip to content

Latest commit

 

History

History
147 lines (112 loc) · 4.99 KB

File metadata and controls

147 lines (112 loc) · 4.99 KB

Template Method

O que é?

O Template Method é um padrão comportamental que define o esqueleto de um algoritmo em uma classe base, permitindo que subclasses sobrescrevam etapas específicas do algoritmo sem alterar sua estrutura geral. O padrão encapsula um algoritmo em uma classe, definindo uma sequência de passos, onde alguns desses passos podem ser sobrescritos pelas subclasses.

Quando usar?

  • Quando você quer permitir que clientes estendam apenas etapas específicas de um algoritmo
  • Quando você tem várias classes que contêm algoritmos quase idênticos
  • Quando você quer localizar código comum entre várias classes em um único lugar
  • Quando você quer controlar em que pontos uma subclasse pode variar um algoritmo

Exemplo em Python

from abc import ABC, abstractmethod

class Relatorio(ABC):
    """Classe abstrata que define o template para geração de relatórios"""
    
    def gerar_relatorio(self) -> None:
        """Template method que define o esqueleto do algoritmo"""
        self.cabecalho()
        self.corpo()
        self.rodape()
        self.formatar_saida()
    
    @abstractmethod
    def cabecalho(self) -> None:
        """Hook method que deve ser implementado pelas subclasses"""
        pass
    
    @abstractmethod
    def corpo(self) -> None:
        """Hook method que deve ser implementado pelas subclasses"""
        pass
    
    def rodape(self) -> None:
        """Método concreto que pode ser sobrescrito opcionalmente"""
        print("\n------- Fim do Relatório -------")
    
    def formatar_saida(self) -> None:
        """Método concreto que pode ser sobrescrito opcionalmente"""
        print("\n================================\n")

class RelatorioVendas(Relatorio):
    def __init__(self, vendas: list[tuple[str, float]]):
        self.vendas = vendas
    
    def cabecalho(self) -> None:
        print("RELATÓRIO DE VENDAS")
        print("Data: 01/01/2024")
        print("================================")
    
    def corpo(self) -> None:
        total = 0.0
        print("\nVendas realizadas:")
        for produto, valor in self.vendas:
            print(f"- {produto}: R$ {valor:.2f}")
            total += valor
        print(f"\nTotal: R$ {total:.2f}")

class RelatorioEstoque(Relatorio):
    def __init__(self, estoque: dict[str, int]):
        self.estoque = estoque
    
    def cabecalho(self) -> None:
        print("RELATÓRIO DE ESTOQUE")
        print("Data: 01/01/2024")
        print("================================")
    
    def corpo(self) -> None:
        print("\nProdutos em estoque:")
        for produto, quantidade in self.estoque.items():
            status = "OK" if quantidade > 10 else "BAIXO"
            print(f"- {produto}: {quantidade} unidades ({status})")
    
    def rodape(self) -> None:
        """Sobrescrevendo o método rodape para adicionar informação adicional"""
        print("\nOBS: Produtos com estoque BAIXO precisam ser repostos")
        super().rodape()

def main():
    # Dados de exemplo
    vendas = [
        ("Notebook", 3500.00),
        ("Mouse", 50.00),
        ("Teclado", 150.00)
    ]
    
    estoque = {
        "Notebook": 5,
        "Mouse": 15,
        "Teclado": 8,
        "Monitor": 12
    }
    
    # Gerando relatório de vendas
    print("\n=== Relatório de Vendas ===")
    relatorio_vendas = RelatorioVendas(vendas)
    relatorio_vendas.gerar_relatorio()
    
    # Gerando relatório de estoque
    print("\n=== Relatório de Estoque ===")
    relatorio_estoque = RelatorioEstoque(estoque)
    relatorio_estoque.gerar_relatorio()

if __name__ == "__main__":
    main()

Vantagens

  1. Permite que clientes sobrescrevam apenas certas partes de um algoritmo grande
  2. Evita duplicação de código ao mover código comum para uma classe base
  3. Facilita a manutenção ao centralizar partes do algoritmo
  4. Permite variações controladas de um mesmo algoritmo
  5. Aplica o princípio "Hollywood" (Don't call us, we'll call you)

Desvantagens

  1. Alguns clientes podem ficar limitados pelo esqueleto do algoritmo
  2. Pode violar o princípio de Substituição de Liskov se o template method sobrescrever um método padrão
  3. Quanto mais passos o template tiver, mais difícil se torna sua manutenção
  4. Pode levar a uma hierarquia de classes rígida

Considerações de Implementação

  1. Defina claramente quais passos são:

    • Abstratos (devem ser implementados)
    • Concretos (implementação padrão)
    • Hooks (podem ser sobrescritos)
  2. Minimize o número de passos abstratos para reduzir o esforço de implementação das subclasses

  3. Considere fornecer implementações padrão para hooks quando possível

  4. Use comentários ou documentação para explicar:

    • A ordem dos passos
    • Quais passos são obrigatórios
    • Quais passos podem ser sobrescritos
    • O propósito de cada passo
  5. Considere usar métodos protegidos para os passos do template para evitar chamadas diretas

  6. Pense em usar o padrão Factory Method em conjunto quando precisar criar objetos dentro do template method