Proxy Pattern

Proxy Pattern

Introduction

The Proxy pattern is a structural design pattern that provides a surrogate or placeholder for another object to control access to it. This is useful for managing operations that are resource-intensive, need to be controlled, or are complex.

Purpose

  • To provide a surrogate or placeholder for another object to control access to it.
  • To act as an intermediary between the client and the real object.

Use Cases

  • When you need a more versatile or sophisticated reference to an object than a simple pointer.
  • For lazy initialization of a heavy object.
  • To control access to the original object for security reasons, to manage its lifecycle, or to add other functionalities like logging and monitoring.

Advantages/Disadvantages

Advantages:

  • Can control the service object without clients knowing about it.
  • Can manage the lifecycle of the service object when clients don’t care about it.
  • The proxy works even if the service object isn’t ready or is not available.

Disadvantages:

  • Can complicate the code due to the introduction of additional classes.
  • Can introduce a slight delay to the real service object’s response time.

Implementation in JavaScript

javascript
	class Subject {
	  request() {}
	}
	
	class RealSubject extends Subject {
	  request() {
	    return 'RealSubject: Handling request.';
	  }
	}
	
	class Proxy extends Subject {
	  constructor(realSubject) {
	    super();
	    this.realSubject = realSubject;
	  }
	
	  request() {
	    if (this.checkAccess()) {
	      this.realSubject.request();
	      this.logAccess();
	    }
	  }
	
	  checkAccess() {
	    // Some condition to control the access
	    console.log('Proxy: Checking access prior to firing a real request.');
	    return true;
	  }
	
	  logAccess() {
	    console.log('Proxy: Logging the time of request.');
	  }
	}
	
	// Usage
	const realSubject = new RealSubject();
	const proxy = new Proxy(realSubject);
	
	console.log(proxy.request());

Practical Example

Consider a scenario in a backend application where we have a database service and we want to add logging and access control whenever a database query is executed.

javascript
	class DatabaseService {
	  executeQuery(query) {
	    console.log(`Executing: ${query}`);
	  }
	}
	
	class DatabaseProxy {
	  constructor(service) {
	    this.service = service;
	  }
	
	  executeQuery(query) {
	    if (this.hasAccess()) {
	      this.logQuery(query);
	      this.service.executeQuery(query);
	    }
	  }
	
	  hasAccess() {
	    // Check for access rights
	    console.log('DatabaseProxy: Checking access rights.');
	    return true; // Assuming access is granted
	  }
	
	  logQuery(query) {
	    console.log(`DatabaseProxy: Logging query - ${query}`);
	  }
	}
	
	// Usage
	const dbService = new DatabaseService();
	const proxy = new DatabaseProxy(dbService);
	
	proxy.executeQuery('SELECT * FROM users');

In this example, DatabaseProxy acts as a proxy to DatabaseService. It adds additional functionalities like access control and logging without changing the original database service’s code.