Conceptly
← All Concepts
πŸ›‘οΈ

Proxy

StructuralA surrogate object that controls access to the real object

Proxy is a structural pattern that places a surrogate object in front of the real object to control access. The Client sends requests through the same interface to the Proxy, and the Proxy performs additional logic -- access control, caching, lazy loading -- before delegating to the real object when necessary. Think of an executive's assistant. External contacts go through the assistant rather than reaching the executive directly. The assistant checks schedules, assesses urgency, and sometimes handles things without involving the executive at all. The requester uses the same communication channel regardless, so the difference is invisible.

β–ΆArchitecture Diagram

πŸ” Structure

Dashed line animations indicate the flow direction of data or requests

Why do you need it?

Direct access to an object is simple, but reality often makes it impractical. Creating database connections on every call is expensive. Letting anyone access sensitive data creates security risks. Using a remote object as if it were local requires network calls. If you solve these problems by sprinkling conditionals into client code, business logic and infrastructure logic become entangled. Access-control code spreads to every call site, and every policy change requires editing multiple locations.

Why did this approach emerge?

In early distributed and enterprise systems, policies such as remote invocation, permission checks, and lazy creation of expensive resources were easy to leak directly into client code. Once every caller had to remember 'check permission first, create if missing, cross the network if remote,' business logic became saturated with infrastructure rules. Proxy emerged from the pressure to pull those access policies out of call sites and gather them behind an object that keeps the same interface as the real target. It later expanded beyond remote calls into lazy loading, AOP, and caching, but the starting point is the same: centralize the cost and rules of access in a surrogate object.

How does it work inside?

Proxy's key property is maintaining the same interface as the real object. The Client depends only on the Subject interface and does not know whether a Proxy or the Real Subject is behind it. The sequence works like this: 1. The Client calls the Subject interface's request(). 2. Inside the Proxy's request(), pre-processing runs: permission checks, cache lookups, log entries. 3. If pre-processing passes, the Real Subject's request() is called via delegation. 4. The Real Subject's result goes through post-processing (cache storage, metric recording) and is returned to the Client. Variants differ by purpose. A Virtual Proxy defers creation of a heavy object until first use. A Protection Proxy verifies the caller's permissions. A Caching Proxy stores results of identical requests to reduce real calls. The structure is the same; only the pre- and post-processing logic changes.

In code

Keeping the same interface while inserting access policy

interface Subject {
  request(): string;
}

class RealReportService implements Subject {
  request() {
    return 'fresh report';
  }
}

class CachingProxy implements Subject {
  private cache?: string;

  constructor(private readonly target: Subject) {}

  request() {
    if (this.cache) return this.cache;
    const result = this.target.request();
    this.cache = result;
    return result;
  }
}

The client only sees Subject. The Proxy keeps the same interface while inserting an access policy such as caching around the real call.

Boundaries & Distinctions

Proxy and Decorator are nearly identical in structure. Both wrap a target object, implement the same interface, and delegate internally. The difference is intent. Proxy exists to control or manage access; Decorator exists to add functionality dynamically. Proxy often manages the target object's lifecycle, while Decorator typically receives the target from the outside. Proxy and Adapter are also compared. Proxy maintains the same interface and controls access; Adapter changes the interface itself. Whether the interface changes or stays the same is the criterion that separates them. 'Is this wrapping meant to control access, add functionality, or change the interface?' -- answering that question tells you whether Proxy, Decorator, or Adapter is the right choice.

When should you use it?

Proxy appears often when separating infrastructure concerns from business logic. In Spring, adding @Transactional causes the framework to create a Proxy around the class that automatically wraps transaction begin and commit. The developer writes only business logic. ORM lazy loading is also Proxy. When user.getOrders() is called, a real DB query fires, but when the user object was loaded, only a Proxy was placed in the orders field, deferring the actual query. Cost is incurred only when needed. However, excessive Proxy use makes debugging harder. When multiple proxies stack in the call chain, tracing the path to the real logic becomes difficult, and additional logic can fire at unexpected points. In most cases, a single Proxy is sufficient.

Lazy loading -- deferring creation of a heavy object until it is actually neededAccess control -- allowing or blocking calls to the real object based on permissionsCaching -- returning cached results for identical requests without calling the real objectLogging and monitoring -- recording logs or collecting metrics before and after real-object calls