Pular para o conteúdo

O Facade é um padrão de projeto estrutural que fornece uma interface simplificada para um conjunto complexo de classes, bibliotecas ou subsistemas. Em vez de o cliente conhecer todos os detalhes de configuração, ordem de chamadas e dependências internas, ele conversa com um único ponto de entrada mais estável e fácil de usar.

Esse padrão aparece com frequência quando uma parte do sistema depende de APIs extensas, frameworks sofisticados ou módulos internos cheios de etapas técnicas. O Facade existe para reduzir atrito de uso, esconder complexidade acidental e diminuir o acoplamento entre o cliente e os detalhes internos do subsistema.

Imagine um sistema acadêmico que precisa gerar certificados em PDF para alunos concluintes. Para isso, a aplicação depende de vários serviços e componentes:

  • um serviço para buscar dados do aluno
  • um serviço para validar conclusão de carga horária
  • um gerador de layout em PDF
  • um assinador digital
  • um serviço de armazenamento do arquivo final
  • um módulo de envio por email

Sem um desenho adequado, o código cliente tende a fazer tudo diretamente:

  • instanciar várias classes técnicas
  • descobrir a ordem correta de execução
  • coordenar dependências manualmente
  • repetir a mesma sequência em vários pontos do sistema
  • depender de classes demais para realizar uma única tarefa de negócio

Esse desenho gera problemas práticos:

  • o cliente fica fortemente acoplado ao subsistema
  • a lógica principal se mistura com detalhes de infraestrutura
  • mudanças internas exigem ajustes em vários chamadores
  • o fluxo fica mais difícil de entender e manter
  • reutilizar a mesma integração se torna mais trabalhoso

O problema central não é apenas ter muitas classes. O problema é expor complexidade demais para quem só precisa executar uma operação de alto nível.

O Facade resolve isso criando uma classe que concentra o acesso ao subsistema por meio de operações mais simples e orientadas ao que o cliente realmente precisa.

  1. Identifique um caso de uso frequente, como emitirCertificado().
  2. Crie uma classe fachada, como ServicoCertificadoFacade.
  3. Faça essa fachada conhecer os componentes internos necessários.
  4. Organize nela a sequência correta das chamadas técnicas.
  5. Exponha ao cliente apenas uma interface pequena e clara.

Assim, o cliente deixa de lidar diretamente com várias classes especializadas e passa a chamar um método de mais alto nível. A complexidade continua existindo, mas fica encapsulada atrás de uma interface mais compreensível.

O ponto central do padrão é este: o cliente acessa um fluxo complexo por meio de uma entrada simples e coesa.

Pense em um atendente de hotel. Para o hóspede, basta pedir ajuda na recepção. O atendente coordena limpeza, manutenção, restaurante, transporte e outros serviços internos sem que o hóspede precise falar com cada setor separadamente.

No Facade, a fachada faz esse papel de recepção. Ela não substitui os departamentos internos, mas simplifica o acesso a eles.

Use Facade quando:

  • um subsistema possui muitas classes ou etapas técnicas
  • o cliente precisa apenas de uma parte mais comum da funcionalidade
  • você quer reduzir o acoplamento entre camadas
  • há fluxos repetidos de integração espalhados pelo sistema
  • a equipe precisa oferecer um ponto de entrada mais estável

Exemplos reais em software moderno:

  • serviço que centraliza autenticação, autorização e geração de token
  • camada que simplifica integração com gateway de pagamento
  • módulo que encapsula geração, assinatura e envio de documentos
  • API interna que coordena várias chamadas para microsserviços
  • serviço que orquestra cache, repositório e serialização de dados

Facade pode ser mal utilizado quando a fachada cresce demais e passa a concentrar responsabilidades sem critério. Alguns erros frequentes são:

  • transformar a fachada em um ponto central com regras demais
  • esconder operações que deveriam continuar explícitas para o cliente
  • usar Facade apenas como apelido para uma classe utilitária gigante
  • misturar orquestração de fluxo com regras de domínio complexas

As consequências incluem fachadas inchadas, baixo encapsulamento real e um novo ponto de acoplamento excessivo.

Facade funciona melhor quando simplifica a entrada para um subsistema, sem virar um objeto deus.

Uma forma incremental de implementar Facade é:

  1. Identifique um fluxo complexo que o cliente executa com frequência.
  2. Liste quais classes do subsistema participam desse fluxo.
  3. Crie uma fachada com um nome orientado ao caso de uso.
  4. Encapsule a ordem das chamadas e a preparação dos dados.
  5. Exponha métodos de alto nível para o cliente.
  6. Mantenha a fachada coesa e evite colocar nela toda a aplicação.

Antes de escrever o código, vale responder: o cliente realmente precisa conhecer todas essas etapas internas? Se a resposta for não, Facade costuma ser uma boa escolha.

No exemplo abaixo, um sistema acadêmico simplifica a emissão de certificados escondendo a interação com vários serviços internos.

class AlunoService {
public String buscarNomeAluno(int alunoId) {
return "Marina Souza";
}
}
class HistoricoService {
public boolean concluiuCurso(int alunoId) {
return true;
}
}
class PdfService {
public String gerarPdf(String conteudo) {
return "certificado.pdf";
}
}
class EmailService {
public void enviar(String arquivo) {
System.out.println("Enviando arquivo por email: " + arquivo);
}
}
class CertificadoFacade {
private AlunoService alunoService = new AlunoService();
private HistoricoService historicoService = new HistoricoService();
private PdfService pdfService = new PdfService();
private EmailService emailService = new EmailService();
public void emitirCertificado(int alunoId) {
if (!historicoService.concluiuCurso(alunoId)) {
System.out.println("Aluno ainda nao concluiu o curso.");
return;
}
String nome = alunoService.buscarNomeAluno(alunoId);
String arquivo = pdfService.gerarPdf("Certificado de conclusao para " + nome);
emailService.enviar(arquivo);
}
}

Nesse código, CertificadoFacade oferece ao cliente um método único de alto nível. O cliente não precisa saber quais serviços participam do fluxo nem em que ordem eles devem ser chamados.

Essa abordagem reduz a complexidade do uso e protege o restante do sistema contra mudanças internas no subsistema.

  • simplifica o uso de subsistemas complexos
  • reduz acoplamento entre cliente e implementação interna
  • melhora legibilidade em fluxos de integração
  • centraliza orquestrações repetidas
  • facilita troca ou evolução de componentes internos
  • pode virar uma classe grande demais
  • pode esconder detalhes importantes em excesso
  • não elimina a complexidade interna do subsistema
  • se mal projetado, cria um novo ponto de acoplamento

O Facade se relaciona com outros padrões importantes:

  • Adapter: Adapter muda a interface para torná-la compatível; Facade cria uma interface mais simples para um conjunto já existente
  • Mediator: Mediator coordena comunicação entre objetos pares; Facade oferece um ponto de entrada simplificado para o cliente
  • Abstract Factory: Abstract Factory abstrai criação de objetos; Facade costuma abstrair uso coordenado de vários objetos já existentes
  • Decorator: Decorator adiciona comportamento mantendo a mesma interface; Facade simplifica acesso a um subsistema
  • Proxy: Proxy controla acesso a um objeto específico; Facade normalmente representa vários objetos e fluxos internos

Essas comparações ajudam a perceber que Facade não existe para adaptar contrato nem para decorar comportamento, mas para reduzir a complexidade percebida pelo cliente.

As formas mais comuns de aplicar Facade são:

  • uma fachada por caso de uso relevante, como pagamento, autenticação ou emissão de documentos
  • fachadas por subsistema, como VideoFacade, PagamentoFacade ou RelatorioFacade
  • fachadas finas que apenas orquestram chamadas
  • fachadas um pouco mais ricas que também validam pré-condições simples

Em sistemas em camadas, é comum que serviços de aplicação exerçam papel parecido com Facade ao oferecer operações de alto nível para controladores e interfaces externas.

Agora veja um caso mais realista em um sistema universitário. A secretaria precisa processar a matrícula de um aluno em uma disciplina sem expor ao controlador todas as etapas técnicas envolvidas.

class AlunoRepository {
public boolean alunoExiste(int alunoId) {
return true;
}
}
class DisciplinaRepository {
public boolean haVagas(String codigoDisciplina) {
return true;
}
}
class FinanceiroService {
public boolean situacaoRegular(int alunoId) {
return true;
}
}
class MatriculaService {
public void matricular(int alunoId, String codigoDisciplina) {
System.out.println("Matricula registrada para o aluno " + alunoId + " em " + codigoDisciplina);
}
}
class NotificacaoService {
public void enviarConfirmacao(int alunoId, String codigoDisciplina) {
System.out.println("Confirmacao enviada para o aluno " + alunoId + " da disciplina " + codigoDisciplina);
}
}
class MatriculaFacade {
private AlunoRepository alunoRepository = new AlunoRepository();
private DisciplinaRepository disciplinaRepository = new DisciplinaRepository();
private FinanceiroService financeiroService = new FinanceiroService();
private MatriculaService matriculaService = new MatriculaService();
private NotificacaoService notificacaoService = new NotificacaoService();
public void processarMatricula(int alunoId, String codigoDisciplina) {
if (!alunoRepository.alunoExiste(alunoId)) {
System.out.println("Aluno nao encontrado.");
return;
}
if (!financeiroService.situacaoRegular(alunoId)) {
System.out.println("Aluno com pendencias financeiras.");
return;
}
if (!disciplinaRepository.haVagas(codigoDisciplina)) {
System.out.println("Nao ha vagas disponiveis.");
return;
}
matriculaService.matricular(alunoId, codigoDisciplina);
notificacaoService.enviarConfirmacao(alunoId, codigoDisciplina);
}
}
public class SistemaAcademico {
public static void main(String[] args) {
MatriculaFacade facade = new MatriculaFacade();
facade.processarMatricula(123, "ENG-SW-301");
}
}

Nesse exemplo, MatriculaFacade esconde validações, verificação de vagas, registro da matrícula e envio de confirmação. O cliente trabalha com uma operação única e mais próxima da linguagem do negócio.

Esse tipo de modelagem funciona bem quando o sistema possui subsistemas técnicos demais para uma tarefa que, do ponto de vista do cliente, deveria parecer simples.