Intuition
Think of a celebrity:
You rarely talk to the celebrity directly.
You talk to their agent, who:
Filters requests
Schedules meetings
Sometimes says “no.”
Passes along only what matters
The agent is a proxy for the celebrity: it looks like the “contact point” but stands in front of the real person, controlling access and sometimes adding behavior.
In software, a proxy object stands in for a “real” object, controlling how and when that real object is used.
Intent of the Proxy pattern
Core idea:
Provide a surrogate or placeholder for another object to control access to it.Important points:
Both proxy and real object implement the same interface, so clients can use them interchangeably.
The proxy holds a reference to the real object (or knows how to create or reach it).
The proxy can:
Delay creation or loading of the real object (lazy loading / virtual proxy)
Check permissions (protection proxy)
Add logging, caching, or other cross‑cutting concerns
Represent a remote object (remote proxy)
The client talks to the proxy, which decides how to delegate to the real object.
Basic structure
Common roles:
Subject
The interface or abstract class that both Proxy and RealSubject use.
RealSubject
The real object that does the actual work.
Proxy
Implements
Subject.Contains a reference/pointer to
RealSubject.Controls access or adds behavior before/after calling the real object.
Client code depends only on Subject and can use either a Proxy or a RealSubject without changing.
C++ example: Virtual proxy for a heavy image
Imagine an image viewer:
Loading a large image from disk is expensive.
You might not need to load it until it is actually displayed.
Subject interface
RealSubject: the actual heavy image
If you create RealImage directly, it loads from disk immediately, even if you never call display().
Proxy: lazy‑loading image
Usage
Here:
ImageProxyandRealImageboth implementImage.Client code uses
Image*And doesn’t care whether it’s talking to a proxy or the real image.The proxy defers the expensive
RealImagecreation untildisplay()is called.
This is a virtual proxy: it controls when the heavy object is instantiated.
Protection proxy example: access control
Suppose you have a sensitive operation:
Real document:
You might want to restrict writing:
The proxy controls who can callwrite, while exposing the same Document interface.
This is a protection proxy.
Common types of proxies
Virtual Proxy
Delays the creation or loading of a heavy object until it’s actually needed.
Example: image loading, large configuration objects, database connections.
Protection Proxy
Checks access rights before forwarding calls.
Example: role‑based access control around sensitive services.
Remote Proxy
Represents an object in another address space (e.g., another machine).
The proxy hides networking details; client code calls methods as if it were local.
Caching / Logging Proxy
Adds caching, logging, or other cross‑cutting concerns around a real service.
All share the same structure: same interface, internal reference, extra behavior around delegation.
Proxy vs Decorator vs Facade
These patterns can feel similar, so it helps to focus on intent:
Proxy
Main goal: control access to an object (when, whether, or how it is used).
Often responsible for lazy loading, security, remote access, or monitoring.
Decorator
Main goal: add behavior to an object without changing its interface.
Typically used to build up additional features (like logging, formatting, add‑ons).
Facade
Main goal: simplify the use of a complex subsystem by providing a high‑level interface.
Quick mental shortcut:
“Stand‑in that decides if/when/how to reach the real thing” → Proxy.
“Wrapper that adds extra functionality to a base object” → Decorator.
“Single simpler entry point to a big system” → Facade.
When to use the Proxy pattern
Proxy is a good fit when:
Creating or loading an object is expensive, and you want lazy initialization.
You need access control around a resource (e.g., based on user role).
The real object lives remotely, but you want a local representative object.
You want to transparently add cross‑cutting behavior (logging, caching) in a controlled place.
It may be unnecessary when:
The real object is trivial to create and use.
You don’t need indirection; direct access is simple and clear.
The extra logic clearly belongs inside the real class itself rather than a separate stand‑in.
A useful cue: if someone says “I want a lightweight placeholder that represents a heavier or more sensitive object,” Proxy is likely appropriate.