The Proxy Pattern provides a surrogate for another object to control access to it. The intent is to control access to a resource-intensive, remote, or secure object.

Components

V.S Decorator

Proxy Decorator
Goal Control access to an object (e.g., security, lazy loading, logging) Add or extend behavior to an object dynamically
Focus Protection, remote access, instantiation control

It can add Control access dynamically and wrap by several proxy (chaining), but these are not the emphasis. | Flexibility(Add dynamically + chaining) in augmenting behavior without changing original class |

Middleware in web servers often behaves like a hybrid of Proxy and Decorator.

SOLID principles

  1. Single Responsibility Principle (SRP): Each proxy class has a single responsibility.
  2. Open/Closed Principle (OCP): Proxy extends a subject function without modifying itself.
  3. Liskov Substitution Principle (LSP): Proxy will call subject’s method the maintain the same purpose.
  4. Dependency Inversion Principle (DIP): Proxy depends on subject’s abstraction.

Implementation

Inheritance

Since the Proxy pattern doesn’t emphasize runtime wrapping like the Decorator does, it can be implemented by inheritance.

// Subject
interface SubjectI {
  request(): void;
}
class Subject implements SubjectI {
  request(): void {
    console.log("Handling request.");
  }
}

// Proxy
class Proxy extends Subject implements SubjectI {
  request(): void {
    console.log("Proxy: Checking access before delegating...");
    super.request();
    console.log("Proxy: Logging after request.");
  }
}

// Client
function compute(subject: Subject) {
  subject.request();
}

compute(new Proxy());

Composition

// Subject
interface SubjectI {
  request(): void;
}
class Subject implements SubjectI {
  request(): void {
    console.log("Handling request.");
  }
}

// Proxy
class Proxy implements SubjectI {
  private subject: Subject;

  constructor(subject: Subject) {
    this.subject = subject;
  }

  request(): void {
    console.log("Proxy: Checking access before delegating...");
    this.subject.request();
    console.log("Proxy: Logging after request.");
  }
}

// Client
function compute(subject: Subject) {
  subject.request();
}

compute(new Proxy(new Subject()));

Go Composition (Embedding)

It allows Anonymous Embedding if: