Skip to content

Proxy Pattern — Control Access to Objects

DodaTech Updated 2026-06-24 4 min read

What You'll Learn

You will learn how the Proxy pattern controls access to a target object, with variants including virtual proxies for Lazy Loading, protection proxies for access control, and remote proxies for Distributed Systems. You will understand the key differences between Proxy and Decorator.

Why It Matters

Loading a high-resolution image before it is visible wastes bandwidth and memory. Deleting a document without checking permissions risks data loss. Proxies intercept these operations, adding Lazy Loading, access control, logging, or Caching without modifying the real subject. The proxy and the real subject share the same interface, so clients never know whether they are talking to a lightweight placeholder or the actual object.

Real-World Use

Object-Relational Mappers return proxy objects that load related data from the database only when first accessed (Lazy Loading). DodaTech's secret store uses a proxy that encrypts values on write and decrypts on read, keeping the core store agnostic to security concerns. If the encryption algorithm changes, only the proxy is updated — the store itself remains untouched.

The Pattern

Subject declares the common interface. RealSubject is the actual object. Proxy holds a reference to RealSubject and controls access to it.

from abc import ABC, abstractmethod

class Image(ABC):
    @abstractmethod
    def display(self) -> str:
        pass

class HighResImage(Image):
    def __init__(self, filename: str):
        self._filename = filename
        self._load_from_disk()

    def _load_from_disk(self):
        self._data = f"[Image data for {self._filename}]"

    def display(self) -> str:
        return f"Displaying {self._filename}: {self._data}"

class ImageProxy(Image):
    def __init__(self, filename: str):
        self._filename = filename
        self._real_image = None

    def display(self) -> str:
        if self._real_image is None:
            self._real_image = HighResImage(self._filename)
        return self._real_image.display()

class SecureImageProxy(Image):
    def __init__(self, filename: str, user_role: str):
        self._real = ImageProxy(filename)
        self._user_role = user_role

    def display(self) -> str:
        if self._user_role != "admin":
            return "Access denied: insufficient permissions"
        return self._real.display()
guest_view = SecureImageProxy("photo.png", "guest")
admin_view = SecureImageProxy("photo.png", "admin")
print(guest_view.display())
print(admin_view.display())
Access denied: insufficient permissions
Displaying photo.png: [Image data for photo.png]

Structure

classDiagram
    class Subject {
        <>
        +request()
    }
    class RealSubject {
        +request()
    }
    class Proxy {
        -realSubject: RealSubject
        +request()
    }
    RealSubject ..|> Subject
    Proxy ..|> Subject
    Proxy --> RealSubject : delegates

Real-World Usage

  • Python weakref.proxy — creates a proxy to an object without increasing its reference count.
  • Java java.lang.reflect.Proxy — generates dynamic proxy classes for interface-based access control.
  • Spring AOP — proxies wrap beans to add Transaction management, security, and logging.
  • Nginx reverse proxy — a remote proxy that forwards requests to backend servers, adding Load Balancing and Caching.
  • ES6 JavaScript Proxy — built-in proxy object that intercepts get, set, has, and other operations.
  • Decorator adds behaviour; Proxy controls access — structurally similar but semantically different.
  • Adapter changes the interface; Proxy preserves the interface.
  • Facade simplifies a subsystem; Proxy controls access to a single object.
  • Lazy Loading is often implemented with a virtual proxy.

Pros and Cons

Pros Cons
Separates cross-cutting concerns from business logic Adds indirection that can complicate debugging
Supports Lazy Loading, Caching, and access control May introduce latency for remote proxies
Follows the Open/Closed Principle Proxies can become tightly coupled to RealSubject interface changes
Can be introduced without changing RealSubject code Overuse leads to excessive proxy layers

The code shows two proxy variants. ImageProxy is a virtual proxy that delays the expensive image loading until display() is actually called. SecureImageProxy is a protection proxy that checks the user's role before delegating. They can also be combined, as demonstrated — SecureImageProxy wraps ImageProxy, which in turn wraps HighResImage. This layering is a key advantage of the Proxy pattern: each concern is isolated in its own class and can be composed independently.

Practice Questions

  1. Implement a logging proxy that records every method call made to a service object with timestamps and parameters.
  2. Compare virtual proxy with lazy initialisation via direct null checks inside the real subject — which is more maintainable?
  3. How would you implement a remote proxy that serialises method calls over HTTP and deserialises responses?
  4. What are the thread-safety implications of a virtual proxy that caches the RealSubject after first creation?

Challenge

Implement a Caching proxy that stores results of expensive method calls and returns cached values for repeated calls with the same parameters. Include cache invalidation.

Real-World Task

Run DodaTech's call graph tracer on your application to identify frequently-called methods that return stable data. Implement a Caching proxy for those methods and measure the latency improvement.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro