Proxy
Control access to an object by wrapping it in a Proxy β add lazy loading, caching, logging, access control, or remote invocation transparently.
Intent & Description
π― Intent
Provide a placeholder that intercepts access to the real object so you can add behavior before or after without the client knowing.
π Context
You need to load a heavy object only when it’s first accessed (lazy init), add access control before operations, cache results of expensive calls, or forward calls to a remote object. Modifying the real object or the client to add this behavior would violate separation of concerns.
π‘ Solution
Create a Proxy that implements the same interface as the real object. Client code talks to the Proxy, not knowing the difference. The Proxy performs its cross-cutting concern (lazy init, auth check, caching, logging) and then delegates to the real object.
Real-world Use Case
Source
π TL;DR
Same interface as the real object, with added behavior in between. Lazy load, cache, auth check, log β all transparent to the client. Common in ORMs, RPC clients, and middleware stacks.
Advantages
- Cross-cutting concerns (auth, caching, logging) added without touching the real object or clients.
- Lifecycle of the real object can be managed transparently by the Proxy.
Disadvantages
- Extra class and indirection for each proxied service.
- Proxy adds latency β every call goes through an extra layer.
class RealImage {
constructor(filename) {
this.filename = filename;
this.loadFromDisk();
}
loadFromDisk() { console.log(`Loading ${this.filename}`); }
display() { console.log(`Displaying ${this.filename}`); }
}
class ProxyImage {
constructor(filename) { this.filename = filename; }
display() {
if (!this.realImage) {
this.realImage = new RealImage(this.filename);
}
this.realImage.display();
}
}