Proxy
O Proxy é um padrão estrutural que cria um objeto intermediário para controlar o acesso a outro objeto.
Em vez de:
Cliente
↓
Objeto Real
temos:
Cliente
↓
Proxy
↓
Objeto Real
O Proxy pode adicionar funcionalidades como:
- Controle de acesso.
- Cache.
- Lazy Loading.
- Logging.
- Monitoramento.
Exemplo de controle de acesso
Criamos uma interface:
interface Document {
read(): void;
}
Objeto real:
class RealDocument
implements Document {
read() {
console.log(
"Lendo documento"
);
}
}
Agora criamos o Proxy:
class DocumentProxy
implements Document {
constructor(
private userRole: string
) {}
read() {
if (
this.userRole !== "admin"
) {
throw new Error(
"Acesso negado"
);
}
const document =
new RealDocument();
document.read();
}
}
Uso:
const document =
new DocumentProxy(
"admin"
);
document.read();
Um usuário comum:
const document =
new DocumentProxy(
"user"
);
document.read();
Receberá:
Acesso negado
Proxy com Cache
Outro exemplo:
class UserProxy {
private cache:
Map<string, User> =
new Map();
constructor(
private api: UserApi
) {}
async getUser(id: string) {
if (
this.cache.has(id)
) {
return this.cache.get(id);
}
const user =
await this.api.getUser(id);
this.cache.set(
id,
user
);
return user;
}
}
O Proxy controla o acesso à API e adiciona cache.
O código cliente continua simples:
const user =
await proxy.getUser(
"123"
);
Lazy Loading
Um Proxy também pode atrasar a criação de um objeto pesado.
Por exemplo:
class ImageProxy {
private image?: RealImage;
display() {
if (!this.image) {
this.image =
new RealImage();
}
this.image.display();
}
}
A imagem real só é carregada quando necessário.
Quando usar?
Proxy é útil para:
Controle de acesso
Cache
Lazy Loading
Logging
Auditoria
Rate Limiting
Monitoramento
A ideia principal é:
Controlar ou adicionar comportamentos ao acesso de um objeto através de um intermediário.
Resumo dos padrões estruturais
PadrãoIdeia principalAdapterFaz interfaces incompatíveis trabalharem juntasBridgeSepara abstração de implementaçãoCompositeTrata objetos individuais e grupos de forma uniformeDecoratorAdiciona comportamentos dinamicamenteFacadeSimplifica o acesso a um sistema complexoFlyweightCompartilha dados para economizar memóriaProxyControla ou intermedia o acesso a outro objeto
Uma forma simples de memorizar:
Adapter
→ "Faça isso funcionar com aquilo"
Bridge
→ "Separe o que é feito de como é feito"
Composite
→ "Trate um e muitos da mesma maneira"
Decorator
→ "Adicione funcionalidades sem alterar a classe"
Facade
→ "Esconda a complexidade"
Flyweight
→ "Compartilhe o que é igual"
Proxy
→ "Controle o acesso"
Os padrões estruturais, no geral, ajudam a resolver problemas relacionados à composição de objetos e classes, tornando o sistema mais flexível, desacoplado e fácil de evoluir.