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:

  • ImageProxy and RealImage both implement Image.

  • Client code uses Image* And doesn’t care whether it’s talking to a proxy or the real image.

  • The proxy defers the expensive RealImage creation until display() 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

  1. Virtual Proxy

    • Delays the creation or loading of a heavy object until it’s actually needed.

    • Example: image loading, large configuration objects, database connections.

  2. Protection Proxy

    • Checks access rights before forwarding calls.

    • Example: role‑based access control around sensitive services.

  3. 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.

  4. 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.