CodeDifficulty: Intermediate3 min

Proxy Template in Python, Java and TypeScript

A virtual proxy that creates the real object on the first request and reuses it after.

The Proxy template is a virtual proxy in its pure form, with the participant names from the class diagram. The real subject announces its own creation, so the output shows exactly when it happens. The steps add each participant in Python, and the tabs give the complete program in three languages, each with its output.

Building the template one participant at a time

Subject

The interface both the proxy and the real subject implement.

py
class Subject(ABC):
    @abstractmethod
    def request(self) -> str: ...

Real subject

The object whose creation is worth putting off.

py
class RealSubject(Subject):
    def __init__(self) -> None:
        print("RealSubject created, an expensive step")

Proxy

Creates the real subject on the first request, then forwards.

py
class Proxy(Subject):
    def __init__(self) -> None:
        self._real: RealSubject | None = None

    def request(self) -> str:
        if self._real is None:
            self._real = RealSubject()
        return self._real.request()

Client

Uses the subject interface and is given the proxy.

py
proxy = Proxy()
client(proxy)
client(proxy)

The complete template

py
from abc import ABC, abstractmethod


class Subject(ABC):
    @abstractmethod
    def request(self) -> str: ...


class RealSubject(Subject):
    def __init__(self) -> None:
        print("RealSubject created, an expensive step")

    def request(self) -> str:
        return "RealSubject handled the request"


class Proxy(Subject):
    def __init__(self) -> None:
        self._real: RealSubject | None = None

    def request(self) -> str:
        if self._real is None:
            self._real = RealSubject()
        return self._real.request()


def client(subject: Subject) -> None:
    print(subject.request())


proxy = Proxy()
print("proxy created, nothing loaded yet")
client(proxy)
client(proxy)
OutputRan with python:3.12-slim (Python 3.12.13)
proxy created, nothing loaded yet
RealSubject created, an expensive step
RealSubject handled the request
RealSubject handled the request
The proxy creates the real subject only when the first request arrives.
java
public class PxTemplate {
    static void client(Subject subject) {
        System.out.println(subject.request());
    }

    public static void main(String[] args) {
        Subject proxy = new Proxy();
        System.out.println("proxy created, nothing loaded yet");
        client(proxy);
        client(proxy);
    }
}

interface Subject {
    String request();
}

class RealSubject implements Subject {
    RealSubject() {
        System.out.println("RealSubject created, an expensive step");
    }

    public String request() {
        return "RealSubject handled the request";
    }
}

class Proxy implements Subject {
    private RealSubject real;

    public String request() {
        if (real == null) {
            real = new RealSubject();
        }
        return real.request();
    }
}
OutputRan with eclipse-temurin:21-jdk (Java 21.0.12)
proxy created, nothing loaded yet
RealSubject created, an expensive step
RealSubject handled the request
RealSubject handled the request
Java places the client first so the source launcher finds `main`; the roles are the same.
ts
interface Subject {
  request(): string;
}

class RealSubject implements Subject {
  constructor() {
    console.log("RealSubject created, an expensive step");
  }

  request(): string {
    return "RealSubject handled the request";
  }
}

class SubjectProxy implements Subject {
  private real: RealSubject | null = null;

  request(): string {
    this.real ??= new RealSubject();
    return this.real.request();
  }
}

function client(subject: Subject): void {
  console.log(subject.request());
}

const proxy: Subject = new SubjectProxy();
console.log("proxy created, nothing loaded yet");
client(proxy);
client(proxy);
OutputRan with node:22-slim (Node 22.23.1), TypeScript 5.9.3
proxy created, nothing loaded yet
RealSubject created, an expensive step
RealSubject handled the request
RealSubject handled the request
The class is named `SubjectProxy`, because `Proxy` is a built-in name in JavaScript.

In each output the proxy exists before the real subject does, the real subject is created once, during the first request, and both requests are handled. The client's code is identical to what it would be with a RealSubject, which is what lets a proxy be added in front of an existing object without editing its callers.

The template is not safe for threads: two first requests at once could both find nothing and create two real subjects. A proxy used from several threads needs a lock around the check, the same race a lazily created singleton has.