Facade
Introdução
Seção intitulada “Introdução”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.
Problema
Seção intitulada “Problema”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.
Solução
Seção intitulada “Solução”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.
- Identifique um caso de uso frequente, como
emitirCertificado(). - Crie uma classe fachada, como
ServicoCertificadoFacade. - Faça essa fachada conhecer os componentes internos necessários.
- Organize nela a sequência correta das chamadas técnicas.
- 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.
Analogia
Seção intitulada “Analogia”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.
Aplicabilidade
Seção intitulada “Aplicabilidade”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
Anti-padrão / Mau uso
Seção intitulada “Anti-padrão / Mau uso”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.
Como implementar
Seção intitulada “Como implementar”Uma forma incremental de implementar Facade é:
- Identifique um fluxo complexo que o cliente executa com frequência.
- Liste quais classes do subsistema participam desse fluxo.
- Crie uma fachada com um nome orientado ao caso de uso.
- Encapsule a ordem das chamadas e a preparação dos dados.
- Exponha métodos de alto nível para o cliente.
- 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.
Exemplo em código
Seção intitulada “Exemplo em código”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
Contras
Seção intitulada “Contras”- 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
Relações com outros padrões/conceitos
Seção intitulada “Relações com outros padrões/conceitos”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.
Implementações alternativas (quando aplicável)
Seção intitulada “Implementações alternativas (quando aplicável)”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,PagamentoFacadeouRelatorioFacade - 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.
Exemplo completo
Seção intitulada “Exemplo completo”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.