Da trilha de TypeScript Este conceito ainda não saiu como card do dia. ir para o card de hoje

TypeScript POO Intermediário

Classes abstratas

Em TypeScript, uma classe abstrata é uma classe que não pode ser instanciada diretamente e serve como base para outras classes. Ela pode conter métodos abstratos (sem implementação) que as subclasses são obrigadas a implementar, além de métodos concretos com código compartilhado.

A palavra-chave abstract marca tanto a classe quanto seus métodos abstratos. Métodos abstratos só podem existir em classes abstratas e não têm corpo. Classes concretas que herdam de uma classe abstrata precisam implementar todos os métodos abstratos, a menos que também sejam abstratas.

A diferença entre classe abstrata e interface é que a classe abstrata pode ter implementação de métodos e estado (propriedades), enquanto a interface define apenas o contrato (métodos e propriedades sem implementação). Uma classe pode estender apenas uma classe abstrata, mas pode implementar várias interfaces.

O padrão Template Method é um uso clássico de classes abstratas: a classe base define o esqueleto de um algoritmo em um método concreto, chamando métodos abstratos que as subclasses implementam. Assim, a estrutura do algoritmo fica fixa na base, mas partes específicas variam nas subclasses.

Pontos-chave

  • abstract class não pode ser instanciada com new; serve apenas como base para herança.
  • Métodos abstract não têm corpo e obrigam as subclasses concretas a implementá-los.
  • Classes abstratas podem ter métodos concretos, propriedades e construtores; interfaces não.
  • Uma classe pode estender uma única classe abstrata, mas implementar várias interfaces.
  • O padrão Template Method usa métodos abstratos para permitir variação de partes de um algoritmo.
template_method.ts
abstract class ProcessadorPagamento {
  // Método concreto que define o esqueleto do algoritmo (Template Method)
  processar(valor: number): void {
    if (!this.validar(valor)) {
      console.log("Pagamento inválido");
      return;
    }
    this.debitar(valor);
    this.notificar(valor);
  }

  // Método abstrato: cada subclasse implementa sua validação
  protected abstract validar(valor: number): boolean;

  // Método abstrato: cada subclasse implementa o débito
  protected abstract debitar(valor: number): void;

  // Método concreto com comportamento padrão
  protected notificar(valor: number): void {
    console.log(`Notificação enviada para pagamento de R$ ${valor}`);
  }
}

class CartaoCredito extends ProcessadorPagamento {
  protected validar(valor: number): boolean {
    return valor > 0 && valor <= 5000;
  }

  protected debitar(valor: number): void {
    console.log(`Cartão de crédito debitado em R$ ${valor}`);
  }
}

class Pix extends ProcessadorPagamento {
  protected validar(valor: number): boolean {
    return valor > 0;
  }

  protected debitar(valor: number): void {
    console.log(`Pix transferido no valor de R$ ${valor}`);
  }
}

// Uso
const cartao = new CartaoCredito();
cartao.processar(1000);

const pix = new Pix();
pix.processar(2000);

// cartao.processar(6000); // saída: Pagamento inválido

Exercícios

  1. 1
    Fácil

    Formas geométricas com classe abstrata

    Crie uma classe abstrata Forma com um método abstrato area(): number e um método concreto descricao(): string que retorna "A área é X". Depois, crie as classes Retangulo e Circulo que estendem Forma e implementam area(). No final, instancie cada uma e exiba a descrição.

    Resolver
  2. 2
    Médio

    Relatório com Template Method

    Implemente uma classe abstrata GeradorRelatorio com o método concreto gerar() que chama os métodos abstratos cabecalho(), corpo() e rodape(), todos retornando string. Crie duas subclasses: RelatorioPDF e RelatorioHTML, que retornam textos diferentes para cada parte. O método gerar() deve juntar as três partes com quebras de linha e imprimir o resultado.

    Resolver
  3. 3
    Desafio

    Pipeline de processamento de dados com Template Method e hook

    Crie uma classe abstrata Pipeline com o método concreto executar(dados: string[]): void que executa as etapas na ordem: preProcessar, processar, posProcessar. preProcessar e processar são abstratos. posProcessar é um hook (método concreto com implementação vazia) que as subclasses podem sobrescrever. Implemente PipelineMaiusculo (transforma cada string em maiúsculas) e PipelineFiltro (remove strings vazias). O método executar deve imprimir o array resultante no formato [ "A", "B" ].

    Resolver

Continue estudando