🚀 Oferta especial: 60% OFF no CrazyStack - Últimas vagas!Garantir vaga →
SOLID

Open-Closed Principle: Restaurante Sistema Implacável

Sistema de restaurante quebra quando adiciona novo prato? OCP resolve isso sem modificar código existente. Matemática severa da extensibilidade.

CrazyStack Team
18 min de leitura
SOLIDTypeScriptOOPDesign Patterns

Por que isso é importante

Sistema de restaurante que quebra a cada novo prato custa R$ 15K+ mensais em bugs. Desenvolvedor sênior ganha 40% mais dominando OCP vs júnior que modifica código existente.

Você adiciona um novo prato no cardápio e o sistema inteiro quebra. Modifica desconto de pizza e hambúrguer para de funcionar. Open-Closed Principle resolve essa matemática venenosa da extensibilidade.

Problema Real: Sistema Frágil

Restaurante precisa calcular preços diferentes por tipo de prato. Pizza tem taxa de forno, hambúrguer tem desconto horário, salada tem adicional orgânico.

❌ Código Ruim (Viola OCP)

function calcularPreco(prato: any): number {
  let preco = prato.precoBase;
  
  if (prato.tipo === 'pizza') {
    preco += 5; // Taxa do forno
  } else if (prato.tipo === 'hamburguer') {
    if (isHorarioPromocional()) {
      preco *= 0.8; // 20% desconto
    }
  } else if (prato.tipo === 'salada') {
    preco += 3; // Adicional orgânico
  }
  
  return preco;
}
1

Novo prato = modificar função existente

2

Mudança em pizza pode quebrar hambúrguer

3

Testes quebram constantemente

Open-Closed Principle: Definição Precisa

Princípio de Ouro

Módulo deve estar aberto para extensão, mas fechado para modificação.

Traduzindo: você adiciona funcionalidade nova sem alterar código que já funciona.

✅ Aberto para Extensão

Pode adicionar novo comportamento facilmente

🔒 Fechado para Modificação

Não altera código fonte existente

Solução: Polimorfismo Estratégico

Orientação a objetos com herança resolve a matemática da extensibilidade. Cada tipo de prato vira uma classe independente.

✅ Classe Abstrata Base

abstract class Prato {
  constructor(
    protected nome: string,
    protected precoBase: number
  ) {}
  
  abstract calcularPreco(): number;
  abstract getDescricao(): string;
}

🍕 Implementação Pizza

class Pizza extends Prato {
  calcularPreco(): number {
    return this.precoBase + 5; // Taxa do forno
  }
  
  getDescricao(): string {
    return `${this.nome} - Pizza artesanal`;
  }
}

🍔 Implementação Hambúrguer

class Hamburguer extends Prato {
  calcularPreco(): number {
    let preco = this.precoBase;
    
    if (this.isHorarioPromocional()) {
      preco *= 0.8; // 20% desconto
    }
    
    return preco;
  }
  
  private isHorarioPromocional(): boolean {
    const hora = new Date().getHours();
    return hora >= 14 && hora <= 17; // 14h às 17h
  }
  
  getDescricao(): string {
    return `${this.nome} - Hambúrguer gourmet`;
  }
}

Extensão Sem Modificação

Restaurante decide adicionar sobremesas no cardápio. Com OCP, você não toca em pizza nem hambúrguer.

🍰 Nova Classe - Sobremesa

class Sobremesa extends Prato {
  constructor(
    nome: string,
    precoBase: number,
    private temCobertura: boolean = false
  ) {
    super(nome, precoBase);
  }
  
  calcularPreco(): number {
    let preco = this.precoBase;
    
    if (this.temCobertura) {
      preco += 4; // Adicional cobertura
    }
    
    return preco;
  }
  
  getDescricao(): string {
    const cobertura = this.temCobertura ? 'com cobertura' : 'simples';
    return `${this.nome} - Sobremesa ${cobertura}`;
  }
}

Resultado Poderoso

Zero modificação em Pizza e Hambúrguer
Testes antigos continuam passando
Sistema mais estável e confiável

Uso Prático do Sistema

💼 Código Cliente

// Sistema do restaurante
const cardapio: Prato[] = [
  new Pizza('Margherita', 25),
  new Hamburguer('Big Burger', 18),
  new Sobremesa('Torta de Chocolate', 12, true),
  new Sobremesa('Pudim', 8, false)
];

// Calculadora de pedido
function calcularPedido(pratos: Prato[]): void {
  let total = 0;
  
  pratos.forEach(prato => {
    const preco = prato.calcularPreco();
    console.log(`${prato.getDescricao()}: R$ ${preco}`);
    total += preco;
  });
  
  console.log(`Total: R$ ${total}`);
}

calcularPedido(cardapio);

Output do Sistema

Margherita - Pizza artesanal: R$ 30
Big Burger - Hambúrguer gourmet: R$ 14.4
Torta de Chocolate - Sobremesa com cobertura: R$ 16
Pudim - Sobremesa simples: R$ 8
Total: R$ 68.4

Vantagens Técnicas Severas

🧪 Testabilidade

Cada classe testada isoladamente sem interferência

🔧 Manutenibilidade

Bug em pizza não afeta hambúrguer

📈 Escalabilidade

Adicionar 50 tipos novos sem risco

⚡ Performance

Polimorfismo otimizado pela JIT

Casos de Uso Avançados

OCP não se limita a cálculo de preços. Aplicação se estende para qualquer comportamento extensível.

1

Sistemas de pagamento: PIX, cartão, boleto

2

Notificações: email, SMS, push, WhatsApp

3

Validações: CPF, CNPJ, email, telefone

Exemplo Sistema Pagamento

abstract class ProcessadorPagamento {
  abstract processar(valor: number): Promise<boolean>;
}

class PagamentoPix extends ProcessadorPagamento {
  async processar(valor: number): Promise<boolean> {
    // Lógica específica do PIX
    return true;
  }
}

class PagamentoCartao extends ProcessadorPagamento {
  async processar(valor: number): Promise<boolean> {
    // Lógica específica do cartão
    return true;
  }
}

Implementação Step-by-Step

1

Identifique variação de comportamento

Onde você tem if/else ou switch extensos

2

Crie classe abstrata base

Defina contrato comum com métodos abstratos

3

Implemente classes concretas

Uma para cada variação de comportamento

4

Use polimorfismo no cliente

Trabalhe com tipo abstrato, não implementações

5

Teste extensibilidade

Adicione nova implementação sem modificar existente

Checklist Open-Closed Principle

Sistema extensível sem modificação
Polimorfismo implementado corretamente
Testes unitários isolados
Abstração estável definida
Baixo acoplamento entre classes
Performance mantida com herança

Próximos Passos

OCP é apenas um dos 5 princípios SOLID. Domine todos para escrever código que escala sem quebrar.

📚 Estude os Outros Princípios

Single Responsibility, Liskov Substitution, Interface Segregation, Dependency Inversion

🛠️ Pratique com Projetos Reais

Implemente em sistema de e-commerce, blog, API REST

Domine SOLID na Prática

Aprenda todos os princípios SOLID com projetos reais