Neste artigo
O Padrão de Projeto Facade (ou Façade) oferece uma interface única e simples para um subsistema complexo. Em vez de o cliente conhecer várias classes e a ordem certa de chamá-las, ele conversa com um objeto só, a fachada, que coordena o trabalho por baixo dos panos.
A fachada não cria regra de negócio nova e não tranca o subsistema: quem precisar de algo específico continua podendo usar as classes internas diretamente. Ela só oferece o caminho mais curto para o uso mais comum.

Observe no diagrama os participantes do padrão:
- Facade (OrderFacade): sabe quais classes do subsistema atendem a cada pedido e em que ordem chamá-las.
- Classes do subsistema (Inventory, PaymentGateway e Shipping): fazem o trabalho de verdade e não sabem que a fachada existe.
- Cliente: usa a fachada em vez de falar com cada classe.
Qual problema o Facade resolve?
Imagine o fechamento de um pedido em uma loja virtual. Para concluir a compra você precisa conferir o estoque, reservar os itens, cobrar o cliente e agendar a entrega, nessa ordem. São três classes diferentes e uma sequência que não pode ser trocada.
Agora pense que esse fechamento acontece em três lugares: no controller do site, em um comando de terminal e em um endpoint da API. Sem a fachada, os três conhecem as três classes e repetem a mesma sequência. No dia em que a regra mudar, você altera em três lugares e torce para não esquecer nenhum. Com o Facade, a sequência mora em um lugar só.
Exemplo do padrão Facade em PHP
Vamos para o código. Primeiro, o pedido, que é só um objeto de dados:
<?php
declare(strict_types=1);
namespace Growthdev\DesignPatterns\Structural\Facade;
final class Order
{
public readonly string $sku;
public readonly int $quantity;
public readonly float $unitPrice;
public readonly string $customer;
public readonly string $address;
public function __construct(string $sku, int $quantity, float $unitPrice, string $customer, string $address)
{
$this->sku = $sku;
$this->quantity = $quantity;
$this->unitPrice = $unitPrice;
$this->customer = $customer;
$this->address = $address;
}
public function total(): float
{
return $this->quantity * $this->unitPrice;
}
}
Agora as três classes do subsistema. Repare que nenhuma delas conhece as outras, e nenhuma conhece a fachada.
<?php
declare(strict_types=1);
namespace Growthdev\DesignPatterns\Structural\Facade;
final class Inventory
{
/** @var array<string, int> */
private array $stock;
/** @param array<string, int> $stock */
public function __construct(array $stock)
{
$this->stock = $stock;
}
public function has(string $sku, int $quantity): bool
{
return ($this->stock[$sku] ?? 0) >= $quantity;
}
public function reserve(string $sku, int $quantity): void
{
$this->stock[$sku] -= $quantity;
printf("Reserved %d x %s\n", $quantity, $sku);
}
}
<?php
declare(strict_types=1);
namespace Growthdev\DesignPatterns\Structural\Facade;
final class PaymentGateway
{
public function charge(string $customer, float $amount): void
{
printf("Charged %.2f to %s\n", $amount, $customer);
}
}
<?php
declare(strict_types=1);
namespace Growthdev\DesignPatterns\Structural\Facade;
final class Shipping
{
public function schedule(string $sku, int $quantity, string $address): void
{
printf("Shipping %d x %s to %s\n", $quantity, $sku, $address);
}
}
E aqui está a fachada. O método placeOrder() é o único que o cliente precisa conhecer. Dentro dele está a sequência inteira: conferir o estoque, reservar, cobrar e agendar a entrega.
<?php
declare(strict_types=1);
namespace Growthdev\DesignPatterns\Structural\Facade;
use RuntimeException;
final class OrderFacade
{
private Inventory $inventory;
private PaymentGateway $payment;
private Shipping $shipping;
public function __construct(Inventory $inventory, PaymentGateway $payment, Shipping $shipping)
{
$this->inventory = $inventory;
$this->payment = $payment;
$this->shipping = $shipping;
}
public function placeOrder(Order $order): void
{
if (!$this->inventory->has($order->sku, $order->quantity)) {
throw new RuntimeException('Out of stock');
}
$this->inventory->reserve($order->sku, $order->quantity);
$this->payment->charge($order->customer, $order->total());
$this->shipping->schedule($order->sku, $order->quantity, $order->address);
}
}
O subsistema continua com as mesmas classes e os mesmos métodos. A fachada só juntou, em uma chamada, o que antes eram quatro.
Testando o exemplo
Os testes mostram três situações: o pedido completo, o pedido sem estoque e o uso direto de uma classe do subsistema depois de passar pela fachada.
<?php
declare(strict_types=1);
namespace Growthdev\DesignPatterns\Tests\Structural\Facade;
use Growthdev\DesignPatterns\Structural\Facade\Inventory;
use Growthdev\DesignPatterns\Structural\Facade\Order;
use Growthdev\DesignPatterns\Structural\Facade\OrderFacade;
use Growthdev\DesignPatterns\Structural\Facade\PaymentGateway;
use Growthdev\DesignPatterns\Structural\Facade\Shipping;
use PHPUnit\Framework\TestCase;
use RuntimeException;
final class FacadeTest extends TestCase
{
public function testExpectFacadeToRunTheWholeCheckout(): void
{
$facade = new OrderFacade(new Inventory(['php-book' => 3]), new PaymentGateway(), new Shipping());
$facade->placeOrder(new Order('php-book', 2, 59.90, 'dev@example.com', '100 Main Street'));
$this->expectOutputString(
"Reserved 2 x php-book\n"
. "Charged 119.80 to dev@example.com\n"
. "Shipping 2 x php-book to 100 Main Street\n"
);
}
public function testExpectNothingToHappenWhenOutOfStock(): void
{
$facade = new OrderFacade(new Inventory(['php-book' => 1]), new PaymentGateway(), new Shipping());
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('Out of stock');
$this->expectOutputString('');
$facade->placeOrder(new Order('php-book', 2, 59.90, 'dev@example.com', '100 Main Street'));
}
public function testExpectSubsystemToRemainAvailable(): void
{
$inventory = new Inventory(['php-book' => 3]);
$facade = new OrderFacade($inventory, new PaymentGateway(), new Shipping());
$facade->placeOrder(new Order('php-book', 2, 59.90, 'dev@example.com', '100 Main Street'));
$this->assertTrue($inventory->has('php-book', 1));
$this->assertFalse($inventory->has('php-book', 2));
$this->expectOutputRegex('/^Reserved 2 x php-book/');
}
}
No primeiro teste, uma única chamada produz as três etapas na ordem certa. No segundo, o estoque não cobre o pedido: a fachada lança a exceção antes de reservar, cobrar ou enviar, e por isso a saída fica vazia. No terceiro, o cliente consulta o Inventory diretamente, o que mostra que a fachada não esconde o subsistema à força.
Quando usar o padrão Facade?
- Quando um subsistema tem muitas classes e a maioria dos clientes só precisa de um uso comum.
- Quando você quer isolar o seu código de uma biblioteca de terceiros ou de um sistema legado.
- Quando quer definir um ponto de entrada para cada camada do sistema e reduzir o acoplamento entre elas.
Um aviso para quem usa Laravel: o recurso que o framework chama de Facade é outra coisa. A documentação do Laravel descreve as facades como “static proxies” para classes do container de serviços, ou seja, um atalho estático para um serviço. O nome é o mesmo, mas o padrão do livro GoF é o que você viu aqui.
Cuidados ao usar o Facade
- A fachada pode virar uma “classe faz-tudo”. Se ela começar a acumular métodos de assuntos diferentes, divida em mais de uma.
- Fachada coordena, não decide. Regra de negócio continua nas classes do subsistema.
- Não use a fachada para proibir o acesso ao subsistema. Se o objetivo é controlar o acesso, o padrão é o Proxy.
Facade, Adapter e Mediator: qual a diferença?
Os três ficam “no meio do caminho” entre objetos, e é por isso que são confundidos. A diferença está na intenção e em quem conhece quem:
| Padrão | O que faz | Quem conhece quem |
|---|---|---|
| Facade | Cria uma interface nova e mais simples para um subsistema | A fachada conhece o subsistema; o subsistema não conhece a fachada |
| Adapter | Converte uma interface que já existe em outra que o cliente espera | O adaptador conhece a classe adaptada |
| Mediator | Centraliza a comunicação entre objetos que colaboram entre si | Os objetos conhecem o mediador e falam com ele; a conversa vai nos dois sentidos |
Esse é mais um padrão estrutural do livro GoF. Para conhecer os outros, veja o artigo Resumo dos Padrões de Projetos.
O código completo deste exemplo, com os testes, está no meu GitHub, na pasta src/Structural/Facade do repositório growthdev-repo/design-patterns.
Veja também: o resumo dos 23 padrões de projeto GoF e os outros padrões estruturais já publicados: Adapter, Bridge, Composite, Decorator, Flyweight, Proxy.
Confiança Sempre!!!
Fontes:
- [1] GAMMA, Erich et al. Padrões de Projeto: Soluções reutilizáveis de software orientado a objetos.
- [2] FREEMAN, Eric; ROBSON, Elisabeth; BATES, Bert; SIERRA, Kathy. Head First Design Patterns.
- [3] Laravel. Facades. https://laravel.com/docs/facades

Continue a conversa