Back to Overview

Proxy Pattern

The Proxy Pattern provides a surrogate or placeholder for another object to control access to it. This pattern is useful when we want to add a layer between client code and an actual service object, allowing us to perform various actions before or after the request gets through to the original object.

Problem

There are scenarios where we need to control access to an object, such as when an object is resource-intensive to create, located remotely, or requires access control. Directly accessing such objects might be inefficient, impractical, or insecure.

Subject Interface RealSubject Proxy Client forwards request

Components

Implementation Example

Let's implement a simple image loading proxy that defers loading large images until they're actually needed.

// Subject Interface
class Image {
    constructor() {
        if (this.constructor === Image) {
            throw new Error("Abstract class cannot be instantiated");
        }
    }
    
    display() {
        throw new Error("Method 'display()' must be implemented");
    }
}

// RealSubject
class HighResolutionImage extends Image {
    constructor(filename) {
        super();
        this.filename = filename;
        this.loadImage();
    }
    
    loadImage() {
        // Simulating a heavy image loading process
        console.log(`Loading high-resolution image: ${this.filename}`);
        // In reality, this would involve actual image loading logic
        this.content = `[Content of ${this.filename}]`;
    }
    
    display() {
        console.log(`Displaying: ${this.content}`);
        return this.content;
    }
}

// Proxy
class ImageProxy extends Image {
    constructor(filename) {
        super();
        this.filename = filename;
        this.realImage = null;
    }
    
    display() {
        // Lazy initialization: create the RealSubject only when needed
        if (this.realImage === null) {
            console.log(`ImageProxy: Loading image on demand`);
            this.realImage = new HighResolutionImage(this.filename);
        }
        
        // Delegate to the RealSubject
        return this.realImage.display();
    }
}

// Client code
function clientCode() {
    // Using proxies for multiple images
    const imageGallery = [
        new ImageProxy("image1.jpg"),
        new ImageProxy("image2.jpg"),
        new ImageProxy("image3.jpg")
    ];
    
    console.log("Application started. No images loaded yet.");
    
    // Only when display() is called, the actual image gets loaded
    console.log("User clicks on the first image:");
    imageGallery[0].display();
    
    console.log("User clicks on the third image:");
    imageGallery[2].display();
}

Interactive Demo

Virtual Proxy: Lazy Image Loading

This demo shows how a proxy can defer loading large images until they're needed. Click on the thumbnails to load the high-resolution versions.

// Proxy demonstration log will appear here

When to Use

Benefits

Real-World Uses