Proxy

A placeholder for another object for a few reasons

The Proxy software design pattern puts another object between the caller and the callee and it is done for several reasons:
  • Remote access. Client communicates with a proxy object as if it was a local resource
  • Virtualizing resources. Client communicates with a proxy object while an expensive object is created.
  • Smart proxy. Client communicates with a proxy object while proxy object performs additional duties. Essentially a Decorator.
  • Protection proxy. Client communicates with a proxy object, which ensures that the client actually has proper access to the resource.
The difference between Decorator and Proxy is that Proxy controls the lifecycle of an object that it contains, while Decorator is controlled by the execution flow. Also, Proxy controls access to an object, while Decorator focuses on adding functionality.
Let's look at some code examples. First, let's define an interface that a resource provider uses, as wel as a "resource:"
interface IResourceProvider {
  getResource(): boolean;
}

class Resource {
  getResource(): boolean {
    console.log("Here you go!");
    return true;
  }
}
The next class is an example of a Proxy with complications. Access to the resource is granted on a random basis. The timeout is added to simulate creation of a large resource.
class ResourceControllerByWhim implements IResourceProvider {
  resource: Resource;
  constructor() {
    this.resource = new Resource();
  }

  getResource(): boolean {
    let whim = Math.floor(Math.random() * 10);
    console.log("whim: ", whim);
    if (whim < 3) {
      console.log("contacting remote resource...");
      setTimeout(() => {
        this.resource.getResource();
        return true;
      }, 1000);
    } else {
      console.log("I don't feel like it, so no.");
      return false;
    }
  }
}
The following class is an example of a Protection Proxy:
class ResourceControllerByPermissions implements IResourceProvider {
  resource: Resource;
  permission: string;
  constructor(permission: string) {
    this.resource = new Resource();
    this.permission = permission;
  }

  getResource(): boolean {
    if (this.permission === "access") return this.resource.getResource();
    else {
      console.log("Access denied");
      return false;
    }
  }
}
Here is what it looks like when run:
/*
whim:  7
I don't feel like it, so no.
whim:  5
I don't feel like it, so no.
whim:  2
contacting remote resource...
Here you go!


----- Permission Proxy access example: no permissions
Access denied
----- Permission Proxy access example: with permissions
Here you go!*/