Design de software

Padrão Facade em Swift: escondendo um subsistema complexo com um único método

O padrão Facade oferece um único ponto de entrada simples para um subsistema que envolve vários objetos. Usando um exemplo de cadastro de usuário em Swift, este artigo explica como centralizar a ordem das chamadas e as diferenças em relação a Adapter, Proxy e Decorator.

4 min de leitura
Imagem de capa de Padrão Facade em Swift: escondendo um subsistema complexo com um único método

Recentemente, voltei a analisar a lógica de cadastro e soltei um suspiro.

Eu só tinha tocado em um botão, mas o View Controller chamava diretamente seis ou sete objetos para validar dados, fazer uma requisição de rede, salvar o token, registrar notificações e muito mais.

Eu precisava reutilizar isso em outra tela, mas não queria copiar toda a ordem e combinação das chamadas.

É exatamente para isso que serve o padrão Facade em Swift.

Em resumo, o padrão Facade envolve um subsistema complexo, formado por vários objetos, em um único método, como signUp(). Quem chama não precisa saber como ele funciona internamente.

As diferenças entre conversão de interfaces, controle de acesso e adição de funcionalidades ficam claras em Comparação entre Adapter, Facade, Proxy e Decorator.

Hoje vou mostrar como aplicar esse padrão com código Swift e, com base na minha experiência, quando ele é útil e quando pode acabar atrapalhando.

O que é o padrão Facade?

Facade originalmente significa “fachada”, a parte frontal de um edifício.

Do lado de fora, você vê apenas uma fachada organizada, mas por dentro há tubulações, fiação e equipamentos complexos.

No software acontece a mesma coisa.

Quando um subsistema tem várias classes que chamam umas às outras, você coloca um único ponto de contato na frente dele.

Quem chama só precisa se comunicar com esse ponto.

A ideia central é um “ponto de entrada simplificado”.

Facade não elimina a complexidade: ele a mantém concentrada em um só lugar e abre apenas uma porta simples para o exterior.

O importante é que ele esconde a implementação interna, em vez de eliminá-la.

As tubulações continuam lá; apenas estão escondidas atrás da parede.


Veja como implementar diretamente em Swift

Só explicar com palavras não ajuda muito, então vamos olhar o código.

Suponha que o fluxo de cadastro tenha três subsistemas: validação, cadastro no servidor e armazenamento do token.

Primeiro, os objetos internos que queremos esconder.

struct Validator { func check(_ email: String) -> Bool { email.contains("@") } }
struct AuthAPI { func register(_ email: String) -> String { "token_\(email)" } }
struct TokenStore { func save(_ token: String) { /* Armazenamento no Keychain */ } }

Se o View Controller chamar os três diretamente, o código ficará bagunçado.

Por isso, o Facade os coordena em seu lugar.

struct SignUpFacade {
    private let validator = Validator()
    private let api = AuthAPI()
    private let store = TokenStore()

    func signUp(email: String) -> Bool {
        guard validator.check(email) else { return false }
        let token = api.register(email)   // Gerenciar a ordem interna somente aqui
        store.save(token)
        return true
    }
}

Agora, quem chama precisa de apenas uma linha.

Assim: SignUpFacade().signUp(email: "[email protected]").

Quem chama não precisa saber que a validação vem primeiro e o token é salvo depois.

Diagrama de um Facade coordenando três subsistemas
Diagrama de um Facade coordenando três subsistemas

Mesmo que a ordem mude ou uma etapa seja adicionada depois, basta alterar o interior do Facade.


Quando usar e quando evitar?

Reuni os critérios que defini depois de usá-lo na prática.

Quando Facade é adequado

  • Quando o código repete, em vários lugares, chamadas a vários objetos sempre na mesma ordem fixa
  • Quando você quer envolver uma biblioteca externa ou um SDK complexo e dar a ele nomes simples, adequados ao seu app
  • Quando o View Controller sabe coisas demais e você quer reduzi-lo

Quando é melhor evitar

  • Quando o subsistema já é simples e há pouco a esconder (você apenas adicionará uma camada desnecessária)
  • Quando é necessário um controle detalhado sempre e, no fim, você precisa ignorar o Facade e chamar os objetos internos diretamente

Quero destacar um ponto importante.

Facade não “bloqueia” o acesso ao interior.

Ele apenas oferece um caminho mais simples; quando necessário, você ainda pode usar os objetos internos diretamente.

Por isso, sua natureza é diferente da de outros padrões que tentam controlar todo o acesso.


Algumas dúvidas frequentes

P. Qual é a diferença entre Facade e uma simples função utilitária?

Uma função utilitária geralmente contém uma funcionalidade independente, enquanto o Facade coordena a colaboração e a ordem entre vários objetos.

A diferença está no que cada um esconde.

P. Precisa ser um protocolo?

Não necessariamente.

Mas, se você quiser substituir o Facade por um objeto falso nos testes, abstraí-lo com um protocolo torna tudo muito mais fácil.

P. Eu confundo isso com o padrão Adapter.

Adapter serve para adaptar interfaces incompatíveis, enquanto Facade serve para apresentar algo complexo de forma simples.

É mais fácil lembrar quando você entende que os objetivos são diferentes.

Foi assim que organizei este código de exemplo em um projeto real
Foi assim que organizei este código de exemplo em um projeto real

Resumo

Sempre que encontrar um conjunto complexo de chamadas, pergunte a si mesmo: “Dá para envolver isso em um único método?”

Só essa pergunta costuma deixar o código muito mais fácil de ler.

Facade não é um padrão chamativo, mas é uma ferramenta confiável, usada com frequência no trabalho real.

Espero que você experimente uma versão simples, começando pelo exemplo de cadastro de hoje.

É exatamente esta a sensação: basta abrir uma única porta limpa
É exatamente esta a sensação: basta abrir uma única porta limpa

Leituras recomendadas