GoF, p. 207 também chamado de Surrogate
Procurador
Proxy
Um substituto com a mesma cara, que controla o acesso ao objeto real.
Fornecer um substituto ou marcador de outro objeto para controlar o acesso a ele.
O cartão de crédito
O cartão representa o dinheiro na sua conta. Onde o dinheiro é aceito, ele também é — mesma “interface”. Mas ele acrescenta controle: verifica limite, exige senha, registra a transação e evita que você carregue a quantia física. O comerciante não sabe nem se importa com a diferença.
Você quer executar algo antes ou depois de acessar um objeto — carregá-lo tarde, verificar permissão, cachear, contar acessos, logar — mas não pode ou não quer alterar a classe dele, e nem espalhar essa lógica em todos os chamadores.
Crie uma classe com a MESMA interface do objeto real. O cliente recebe o proxy sem perceber; o proxy faz o trabalho extra e delega ao objeto real quando (e se) for o caso.
- Verificação de permissão duplicada em todos os métodos de um serviço.
- Objetos caros carregados na inicialização e quase nunca usados.
Estrutura
- ServiceInterface
- Interface compartilhada por proxy e serviço real.
- Service
- A classe que faz o trabalho de verdade.
- Proxy
- Guarda a referência ao serviço, controla acesso e delega.
- Client
- Programa contra a interface; não sabe se fala com proxy ou serviço.
- Virtual — adia a criação de um objeto caro até o primeiro uso real.
- Remoto — representa localmente um objeto que vive em outro processo/máquina.
- De proteção — verifica permissões antes de deixar passar.
- De log / smart reference — registra acessos, conta referências, libera recursos.
- De cache — guarda resultados de chamadas repetidas.
Implementação
class RepositorioDocumentos {
buscar(id) { throw new Error('abstrato'); }
}
// ── Serviço real: caro de instanciar ──────────────────
class RepositorioReal extends RepositorioDocumentos {
constructor() {
super();
console.log('🐢 abrindo conexão + carregando índice (2s)…'); // custo alto
this.docs = new Map([[1, { id: 1, titulo: 'Contrato', sigilo: 'alto' }]]);
}
buscar(id) { console.log(`💾 lendo do disco: ${id}`); return this.docs.get(id); }
}
// ── Proxy: virtual (lazy) + proteção + cache ──────────
class RepositorioProtegido extends RepositorioDocumentos {
#real = null; // ainda NÃO existe
#cache = new Map();
constructor(usuario) { super(); this.usuario = usuario; }
#obterReal() {
// Proxy VIRTUAL: só paga os 2 segundos se alguém realmente usar.
if (!this.#real) this.#real = new RepositorioReal();
return this.#real;
}
buscar(id) {
// Proxy de PROTEÇÃO
if (this.usuario.papel !== 'admin') throw new Error('🚫 acesso negado');
// Proxy de CACHE
if (this.#cache.has(id)) { console.log(`⚡ cache: ${id}`); return this.#cache.get(id); }
const doc = this.#obterReal().buscar(id);
this.#cache.set(id, doc);
return doc;
}
}
// Nenhum objeto real foi criado ainda — construir o proxy é instantâneo.
const repo = new RepositorioProtegido({ papel: 'admin' });
repo.buscar(1); // 🐢 constrói agora, 💾 lê do disco
repo.buscar(1); // ⚡ cache
const visitante = new RepositorioProtegido({ papel: 'leitor' });
try { visitante.buscar(1); } catch (e) { console.log(e.message); } // 🚫 — e nada foi carregado - java.lang.reflect.Proxy e proxies dinâmicos de ORMs (lazy loading do Hibernate)
- O objeto `Proxy` nativo do JavaScript
- Service mesh / API gateway — proxies em nível de infraestrutura
Consequências
- Controla o objeto de serviço sem que o cliente saiba.
- Gerencia o ciclo de vida do objeto real (criação tardia, liberação).
- Funciona mesmo com o serviço indisponível ou remoto.
- Novos proxies entram sem alterar clientes nem o serviço (Aberto/Fechado).
- Mais uma camada — resposta pode ficar mais lenta.
- Mais classes para manter.
- Carregamento tardio de objetos pesados (proxy virtual).
- Controle de acesso por permissão (proxy de proteção).
- Objeto remoto representado localmente (proxy remoto).
- Log, métricas ou cache transparentes.
- Você quer ADICIONAR comportamento combinável escolhido pelo cliente — isso é Decorator.
Relações com outros padrões
- Flyweight
- Proxy pode ser o ponto onde o objeto compartilhado é resolvido.
Verificação
Proxy e Decorator têm estrutura idêntica. Qual pista prática melhor os distingue?
- Quem controla o objeto envolvido: o Proxy normalmente o cria e gerencia sozinho; o Decorator recebe pronto e serve para empilhar comportamento escolhido pelo cliente
- Proxy só funciona com objetos remotos
- Decorator não pode ser aninhado
- Proxy é sempre mais rápido
A intenção decide: controlar acesso e ciclo de vida (Proxy) versus enriquecer comportamento de forma combinável (Decorator).