EstruturalIniciante5 min de leitura8 seções1994, Marco de referência: a ideia é mais velha que a data

Facade

Oferece uma interface simples e de alto nível para um subsistema complexo, escondendo a coreografia entre as peças atrás de um único ponto de entrada.

Em 10 segundos

Um subsistema com muitas peças ganha um ponto de entrada único com operações de alto nível: o cliente chama 'finalizarPedido' e a facade coordena estoque, pagamento, frete e notificação por dentro.

  • #simplificacao
  • #subsistema
  • #ponto-de-entrada
  • #gof
Analogia

A recepcionista do hotel

No hotel você não liga para a governança pedir toalhas, para o restaurante reservar mesa e para a central de táxis marcar corrida — você liga para a recepção, e um balcão só resolve tudo. A recepcionista conhece cada setor, a ordem das coisas e os ramais certos; você conhece um número. E se um dia você quiser negociar direto com o chef, o restaurante continua lá — a recepção é conveniência, não muralha.

01Conceito

O problema

Subsistemas crescem: finalizar um pedido envolve estoque, pagamento, frete e notificação, cada um com sua API e seus pré-requisitos. Sem um ponto de entrada, cada cliente reimplementa essa coreografia.

O resultado é acoplamento espalhado: o checkout web, o app e o job de recompra conhecem as mesmas seis classes — e qualquer mudança interna quebra os três.

A raiz é a falta de uma fronteira: sem facade, a 'interface pública' do subsistema é a soma de todas as suas classes, e a Lei de Deméter morre no cliente — que navega objeto por objeto para montar a operação. O conhecimento sobre COMO o subsistema funciona vaza para quem só queria USÁ-LO.

Não confunda com Adapter: o Adapter TRADUZ uma interface existente para outra que o cliente espera (contratos incompatíveis, geralmente 1-para-1); a Facade SIMPLIFICA — cria uma interface nova, menor e de nível mais alto sobre várias peças (1-para-muitos). Adapter é sobre compatibilidade; Facade é sobre conveniência.

Também não é um Mediator: a facade só conhece o subsistema e o coordena de fora — as peças não sabem dela. No Mediator, os colegas conhecem e conversam através do mediador. E note o parentesco com camadas de serviço: um application service em DDD é, na prática, uma facade sobre o domínio.

Como se organiza
  • Clienteconhece só finalizarPedido()

  • CheckoutFacadea única porta de entrada

    • Estoque1. reserva os itens

    • Pagamento2. cobra

    • Frete3. agenda a entrega

Os três subsistemas ficam atrás da facade, não em fila: ela chama cada um na ordem certa, e nenhum deles conhece os outros. O cliente enxerga uma chamada só.
Passo a passoO fluxo, passo a passo
  1. 1

    Identificar a coreografia

    Liste as peças e a ordem que o cliente hoje repete à mão.

  2. 2

    Criar a operação de alto nível

    A facade expõe algo como finalizarPedido() com vocabulário de negócio.

  3. 3

    Orquestrar por dentro

    Ela chama estoque, pagamento, frete… na ordem certa e traduz erros.

  4. 4

    Cliente fala só com a porta

    Uma chamada; o subsistema continua acessível a quem precisa de controle fino.

02Anatomia

Navegue pelas camadas

Camada 1/3Cliente

Camada 1

Cliente

pede a operação de negócio

Chama a facade com a intenção completa ('finalizar pedido com estes itens') e recebe o resultado de alto nível. Não importa, não conhece e não instancia as peças internas.

No código

checkout.finalizarPedido(itens, 150, endereco, email);

Se violar: se o cliente importa uma classe interna 'só desta vez', o acoplamento que a facade eliminou volta a se espalhar.

03Estrutura

Estrutura

Diagrama de classes
04Implementação

Código

// Subsistema: cada peça tem sua propria API, cheia de detalhes
class Estoque {
  reservar(itens: string[]): string { return "res-42"; }
}
class Pagamento {
  cobrar(valor: number): string { return "pay-99"; }
}
class Frete {
  agendar(endereco: string): Date { return new Date(); }
}
class Notificacao {
  confirmar(email: string, previsao: Date): void {}
}

// Facade: uma operacao de alto nivel esconde a coreografia
class CheckoutFacade {
  constructor(
    private estoque = new Estoque(),
    private pagamento = new Pagamento(),
    private frete = new Frete(),
    private notificacao = new Notificacao(),
  ) {}

  finalizarPedido(itens: string[], valor: number, endereco: string, email: string): void {
    const reserva = this.estoque.reservar(itens);
    const cobranca = this.pagamento.cobrar(valor);
    const previsao = this.frete.agendar(endereco);
    this.notificacao.confirmar(email, previsao);
    console.log("Pedido ok:", reserva, cobranca);
  }
}

// Cliente: uma chamada, zero conhecimento do subsistema
new CheckoutFacade().finalizarPedido(["sku-1"], 150, "Rua A, 10", "ana@ex.com");
05No mundo real

Casos de uso

SDK de gateway de pagamentos

Cenário

Cobrar um cartão envolve tokenização, análise antifraude, autorização na adquirente e captura — quatro serviços com protocolos próprios que nenhum lojista quer conhecer.

Como o padrão entra

O SDK expõe uma facade: pagamentos.cobrar(cartao, valor). Por dentro, tokeniza, consulta o antifraude, autoriza e captura na ordem certa. A 'developer experience' de gateways como Stripe é essencialmente uma boa facade.

Trade-off: Casos avançados (captura parcial, pré-autorização longa) não cabem na operação simples — o SDK precisa expor também a API granular, senão vira camisa de força.

Processamento de vídeo em streaming

Cenário

Uma plataforma de vídeo converte uploads: demux, decodificação, filtros, re-encoding em múltiplas resoluções, empacotamento HLS — o ffmpeg tem centenas de flags para isso.

Como o padrão entra

Uma VideoFacade expõe transcodificar(arquivo, perfil). Os perfis ('720p-web', '4k-tv') encapsulam as combinações de flags validadas pelo time de mídia; o resto do sistema nunca vê uma flag do ffmpeg.

Trade-off: Cada necessidade nova vira pedido de perfil novo ao time dono da facade — a conveniência centraliza também a fila de manutenção.

Onboarding em banco digital

Cenário

Abrir uma conta exige KYC (documento + selfie), consulta a bureaus, criação da conta no core bancário, emissão de cartão e chave Pix — cinco sistemas, alguns de fornecedores externos.

Como o padrão entra

Uma OnboardingFacade expõe abrirConta(dadosCliente) e coordena os cinco passos, traduzindo erros de cada fornecedor em um resultado único. O app conversa com uma operação; a complexidade regulatória mora atrás do balcão.

Trade-off: Fluxos longos e parcialmente assíncronos (KYC pode levar horas) não cabem numa chamada síncrona — a facade precisa devolver estados intermediários, e a 'interface simples' fica menos simples.

A fachada que vaza o que deveria esconder

Compila, roda, passa no code review. E quebra depois.

A fachada simplifica a chamada, mas devolve — ou aceita — os tipos do subsistema que ela existia para esconder. Quem usa continua acoplado ao que estava atrás; só o caminho ficou mais curto.

import type { PgResult, PgError } from "pg";
import type { S3Object } from "@aws-sdk/client-s3";

class FachadaDePedido {
  // Parece simples... e devolve o tipo do driver do banco.
  async buscar(id: string): Promise<PgResult> { /* ... */ }

  // ... e aceita o tipo do SDK da AWS.
  async anexar(id: string, obj: S3Object): Promise<void> { /* ... */ }

  // ... e deixa escapar o erro do driver.
  async pagar(id: string): Promise<void> {
    try { /* ... */ } catch (e) { throw e as PgError; }
  }
}

// Quem usa a fachada agora importa 'pg' e o SDK da AWS.
// Trocar Postgres por outro banco continua tocando a aplicacao inteira —
// exatamente o que a fachada prometia evitar.

O que quebra

  • Ao trocar a dependênciaA migração toca todos os chamadores, porque os tipos do subsistema entraram na assinatura pública.
  • No testeSimular a fachada exige construir objetos do driver real, o que é quase tão trabalhoso quanto usar o driver.
  • No `package.json`A dependência que deveria ser interna aparece como dependência direta de módulos que nunca deveriam conhecê-la.

A saída: A fronteira da fachada é a assinatura, não a quantidade de linhas economizadas. Tipos de entrada, de saída e de erro precisam ser seus. Se traduzir tudo parecer caro demais, o problema pode ser que ali não cabia uma fachada.

07Cuidado

Armadilhas

  1. Facade que vira god object

    Começa coordenando, depois valida, depois calcula desconto, depois grava log... Quando a facade acumula regra de negócio, o subsistema vira detalhe e ela vira o monólito interno que todos temem tocar. Facade coordena; regra mora nas peças.

  2. Abstração que vaza

    Se finalizarPedido() retorna o objeto ReservaEstoque interno ou lança PagamentoAdquirenteException crua, o cliente acopla nos tipos do subsistema do mesmo jeito — só que agora com uma classe a mais no meio. A facade precisa traduzir entradas, saídas e erros para o seu próprio vocabulário.

  3. Balcão bonito, bagunça atrás

    Facade esconde complexidade, não a conserta. Usá-la para 'embrulhar' um módulo caótico e declarar o problema resolvido só adia a dor: a bagunça continua crescendo, agora invisível. Se o subsistema está podre, a facade é o primeiro passo (isolar), não o último (refatorar por trás dela).

08Decisão

Quando usar × quando evitar

Use quando

3
  • Uma operação de negócio exige coordenar várias classes numa ordem específica, e vários clientes repetem essa coreografia.
  • Você quer isolar o resto do sistema de uma biblioteca ou subsistema complexo (um ffmpeg, um SDK verboso).
  • Definir a fronteira pública de um módulo: fora dele, só se fala com a facade.

Evite quando

2
  • O subsistema já é simples — a facade vira só um repasse burocrático de chamadas.
  • Os clientes precisam do controle fino que a facade esconde; forçá-los a passar por ela gera métodos com dezenas de parâmetros.

Testar o que ficou

3 armadilhas de Facade viram perguntas, com o nome do padrão escondido, misturadas com padrões parecidos.

Onde isto aparece de verdade

Você já usa isto, talvez sem saber o nome.

  • fetchUma função esconde DNS, TLS, connection pooling, redirecionamento e parsing de resposta.
  • Um ORMuser.save() no lugar de montar transação, SQL, binding de parâmetro e tratamento de erro.

O padrão em uma linha

Sem nome de domínio, sem cerimônia. Só a ideia.

// Uma chamada no lugar de seis, com os tipos que sao seus.
await pedidos.confirmar(pedidoId);

O que ele cobra

1 salto a mais entre a chamada e o efeito.

  • Cada operação nova do subsistema precisa ser exposta de novo
  • Recursos legítimos ficam inacessíveis até alguém adicioná-los à fachada

Não vale se: o subsistema já tem uma interface pequena e estável. Fachada sobre fachada só adiciona um salto.

Costuma ser confundido com

Onde isto aparece

Continue por aqui