Design Patterns: Proxy
Proxy provides a surrogate for another object, controlling access to it. Client code thinks it's talking directly to the real object; it's actually going through the proxy.
Intent
Proxy provides the same interface as the real object and performs additional operations before or after forwarding the request — without changing how clients use it.
Three main use cases:
- Virtual Proxy: defers creating an expensive object until it's actually needed
- Protection Proxy: controls access and validates permissions
- Remote Proxy: wraps the details of communicating with a remote object
Types of Proxies
Caching Proxy: stores results and avoids repeating expensive operations. This is the most common application in practice.
Practical Example: Caching Proxy
interface DataService {
fetchUser(id: string): Promise;
}
// the real implementation
class RealDataService implements DataService {
async fetchUser(id: string): Promise {
console.log(`Calling API: /users/${id}`);
// imagine this is a slow network request
return { id, name: 'Alice', email: 'alice@example.com' };
}
}
// Caching Proxy — same interface, adds a cache layer
class CachedDataService implements DataService {
private cache = new Map();
constructor(private realService: DataService) {}
async fetchUser(id: string): Promise {
if (this.cache.has(id)) {
console.log(`Cache hit: ${id}`);
return this.cache.get(id)!;
}
const user = await this.realService.fetchUser(id);
this.cache.set(id, user);
return user;
}
}
// client only knows the DataService interface
async function main() {
const service: DataService = new CachedDataService(new RealDataService());
await service.fetchUser('123'); // API call
await service.fetchUser('123'); // cache hit
await service.fetchUser('456'); // API call
await service.fetchUser('456'); // cache hit
}
main(); The client has no idea caching is happening. CachedDataService is fully interchangeable with RealDataService.
When to Use
Good fits
- Lazy initialization of expensive resources (Virtual Proxy)
- Access control and permission checks (Protection Proxy)
- Result caching (Caching Proxy)
- Logging operations without modifying the real object
Proxy vs. Decorator
Proxy controls access. Decorator adds behavior. The structures look similar, but the intent is different.
Summary
Proxy is everywhere in modern web development: JavaScript's built-in Proxy object, Vue.js reactivity, Angular's HttpClient interceptors — all of these are this pattern in action.
The core idea: control access to and behavior around an object without changing its interface.