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?

Proxy is classified as a structural pattern in the GoF design patterns. As distributed systems became common, Remote Proxy -- treating remote objects as local -- gained early attention. Distributed technologies such as Java RMI and CORBA used the Proxy pattern as a core mechanism. Today, Proxy's use has broadened. JavaScript's Proxy object, Spring's AOP proxies, ORM lazy loading, API Gateways, and reverse proxy servers all operate on the same principle. The structure of 'placing a surrogate in front of the real target to handle additional logic' repeats from the programming-language level all the way to the infrastructure level.

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.

What is it often confused with?

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