Proxy Pattern
Proxy Pattern
Provide a surrogate or placeholder for another object to control access to it.
Intent
Proxy implements the same Subject interface as the real object (RealSubject). The client works with the Proxy as if it were the RealSubject; the Proxy forwards calls to the RealSubject, with additional logic around the forwarding. Proxy is about controlling access — not about adding behaviour (Decorator) or converting interfaces (Adapter). The client code is entirely unaware of whether it holds a direct reference to the RealSubject or a Proxy.
When NOT to Use
- The proxy's indirection adds measurable latency on a hot code path with high call frequency
- The added concern (logging, caching) can be handled more directly with a simple guard or wrapper without the full pattern overhead
- The interface would need to change for the proxy to work — use Adapter instead
When to Use
- Lazy initialisation of an expensive resource (Virtual Proxy)
- Access control to a resource based on permissions (Protection Proxy)
- Local representation of a remote resource to hide network complexity (Remote Proxy)
- Adding a cross-cutting concern (logging, caching) without modifying RealSubject (Smart Reference / Cache Proxy)
How It Works
All four GoF Proxy variants:
- Virtual Proxy: Defers expensive construction until first use — used as code example below
- Remote Proxy: Represents an object in a different address space (RPC stub, HTTP client) — ancestor of Ambassador (Phase 14)
- Protection Proxy: Controls access based on caller permissions
- Smart Reference / Cache Proxy: Adds caching, reference counting, or logging around the real object
Participants: Subject (interface), RealSubject (implements Subject, does real work), Proxy (implements Subject, holds RealSubject reference, controls access), Client (works with Subject interface, never knows whether it holds a Proxy or RealSubject).
Class Diagram
classDiagram
class Subject {
<<interface>>
+request()*
}
class RealSubject {
+request()
}
class Proxy {
-realSubject : RealSubject
+request()
}
Subject <|.. RealSubject
Subject <|.. Proxy
Proxy o-- RealSubject : delegates to
note for Proxy "Variants:\n- Virtual: lazy-loads RealSubject\n- Protection: access-control checks\n- Remote: network call to RealSubject"
TypeScript Example
// Proxy — TypeScript (Virtual Proxy — defers expensive construction)
// Source: GoF Design Patterns, p.207
interface Image {
display(): void;
}
class RealImage implements Image {
constructor(private filename: string) {
this.loadFromDisk(); // expensive
}
private loadFromDisk() { console.log(`Loading ${this.filename}`); }
display() { console.log(`Displaying ${this.filename}`); }
}
class ProxyImage implements Image {
private real?: RealImage;
constructor(private filename: string) {}
display() {
if (!this.real) this.real = new RealImage(this.filename);
this.real.display();
}
}Java Example
// Proxy — Java (Virtual Proxy)
// Source: GoF Design Patterns, p.207
interface Image { void display(); }
class RealImage implements Image {
private final String filename;
RealImage(String f) { this.filename = f; loadFromDisk(); }
private void loadFromDisk() { System.out.println("Loading " + filename); }
public void display() { System.out.println("Displaying " + filename); }
}
class ProxyImage implements Image {
private RealImage real;
private final String filename;
ProxyImage(String f) { this.filename = f; }
public void display() {
if (real == null) real = new RealImage(filename);
real.display();
}
}Lineage Forward
Proxy → Ambassador → Sidecar lineage:
- Ambassador-Pattern (created Phase 14): A deployment-level Remote Proxy specialised for cross-service communication. The Ambassador runs as a sidecar and handles retries, timeouts, and service discovery on behalf of the service.
- Sidecar-Pattern (created Phase 14): The infrastructure unit that implements Ambassador. The Sidecar pattern is the deployment mechanism; Ambassador is a specialised Sidecar role.
- Service-Mesh-Pattern (created Phase 14): A service mesh is a network of Sidecars (each acting as a Proxy) providing uniform cross-cutting concerns across all services.
Related Concepts
| Pattern | Relationship |
|---|---|
| Decorator-Pattern | Both wrap an object with the same interface; Proxy controls access, Decorator adds behaviour. See Decorator-vs-Proxy-vs-Adapter |
| Adapter-Pattern | Adapter changes the interface; Proxy preserves it and controls access. See Decorator-vs-Proxy-vs-Adapter |
| Flyweight-Pattern | Both involve indirection; Flyweight shares state, Proxy controls access to a single real object |
| Ambassador-Pattern | Deployment-level Remote Proxy for cross-service communication (created Phase 14) |
| Sidecar-Pattern | Infrastructure unit that implements the Ambassador; Sidecar → Ambassador → Service Mesh (created Phase 14) |
Related Security Patterns
- Zero-Trust-Architecture — the GoF Proxy pattern is the conceptual ancestor of infrastructure proxies (Sidecar, Service Mesh) that enforce Zero Trust network plane controls via mutual TLS and policy enforcement at the proxy layer
Sources
- Gamma, Helm, Johnson, Vlissides — Design Patterns, Addison-Wesley, 1994, p.207
Backlinks
Notes that link here: GoF-Patterns-MOC, Decorator-vs-Proxy-vs-Adapter