Stand in for a real object to control access to it — lazily creating it, caching it, or gating who can reach it.
An image gallery shouldn't load full-resolution images until they actually scroll into view, and an admin API shouldn't run a query for a user without permission — but the code calling `image.render()` or `api.query()` shouldn't have to know any of that.
The proxy implements the same interface as the real object. Callers hold the proxy and never know the difference; the proxy decides when (or whether) to forward the call to the real object underneath.
The first call for a given id hits the real service; every later call for the same id returns the cached result instantly.
const RealUserService = {
async fetchUser(id) {
console.log(`network: fetching user ${id}`);
return { id, name: `User ${id}` };
},
};
class CachingUserServiceProxy {
#cache = new Map();
async fetchUser(id) {
if (this.#cache.has(id)) {
console.log(`cache: hit for user ${id}`);
return this.#cache.get(id);
}
const user = await RealUserService.fetchUser(id);
this.#cache.set(id, user);
return user;
}
}
const service = new CachingUserServiceProxy();
await service.fetchUser(1); // network: fetching user 1
await service.fetchUser(1); // cache: hit for user 1