Proxy Design Pattern in JavaScript

1. Definition

The Proxy Design Pattern provides a surrogate or placeholder for another object to control access to it. The proxy can add behaviors such as access control, lazy initialization, logging, or any preprocessing before delegating the task to the original object.

2. Problem Statement

Imagine you have a large object that's resource-intensive to create and you don't want to instantiate this object unless it's necessary. Alternatively, you might want to control access to an object, ensuring certain conditions are met before an operation is performed on it.

3. Solution

Using a proxy, we can delay the instantiation of the real object until it's needed, or add any additional logic before delegating the request to the real object. The proxy should have the same interface as the original object to ensure interchangeability.

4. Real-World Use Cases

1. Image or video loading in web pages where actual loading happens only when they are in the viewport.

2. Access control for certain operations on a remote server.

3. Caching requests to reduce repeated operations or API calls.

5. Implementation Steps

1. Identify the common interface for the RealObject and Proxy.

2. Create the RealObject with the actual operations.

3. Create the Proxy class with a reference to the RealObject and implement operations with additional behavior.

6. Implementation in JavaScript

// Common interface
class Subject {
    request() {}
}
// RealObject with the actual operations
class RealObject extends Subject {
    request() {
        console.log("RealObject handling request.");
    }
}
// Proxy class
class ProxyObject extends Subject {
    constructor() {
        super();
        this.realObject = null;
    }
    request() {
        // Lazy instantiation: creating the RealObject only when needed
        if (!this.realObject) {
            this.realObject = new RealObject();
        }
        console.log("Proxy doing some preprocessing.");
        this.realObject.request();
        console.log("Proxy doing some postprocessing.");
    }
}
// Client Code
const proxy = new ProxyObject();
proxy.request();

Output:

Proxy doing some preprocessing.
RealObject handling request.
Proxy doing some postprocessing.

Explanation:

1. Subject is the common interface for RealObject and ProxyObject.

2. RealObject provides the actual implementation of the request.

3. ProxyObject maintains a reference to a RealObject. The proxy can add behaviors before or after delegating the task to the RealObject.

4. In the client code, when a request is made on the proxy, the proxy handles the request by adding preprocessing, then delegating the task to the RealObject, and finally, adding postprocessing.

7. When to use?

The Proxy pattern is useful when:

1. There's a need for a more versatile or sophisticated reference to an object than a simple pointer.

2. Objects need to be created on demand, especially when they are resource-intensive.

3. Access to an object should be controlled or monitored.

4. Actions (like caching) need to be executed before accessing the real functionality of an object.


Comments