Easy patterns: Proxy

Ruslan Malogulko
ITNEXT
Published in
4 min readFeb 11, 2019

--

This article is created in continuation of easy patterns series description and presents a structural pattern named a Proxy which provides a placeholder for another object to control access to it.

Please refer to the other pattern articles as well:

Creational patterns:

Simple Factory

Factory method

Builder

Singleton

Abstract factory

Prototype

Structural patterns:

Adapter

Decorator

Bridge

Composite

Facade

Flyweight

Proxy (this article)

Behavioral patterns:

Visitor

Mediator

Observer

Memento

Iterator

Chain Of Responsibility

Strategy

State

The main essence

Proxy pattern is useful in cases where a more versatile and sophisticated reference to an object is needed than a simple pointer. Proxy forwards requests to the Subject when appropriate, depending on the kind of proxy.

Some general kinds of proxy are:

  • a remote proxy — provides a local representation of some remote object (for example collects some data chunks before send it to the server to save to avoid extra load for a network)
  • a virtual proxy — replaces expensive object with lightweight representation. Creates such expensive object only on demand (for example image placeholder. User scrolls to the appropriate place in the document and only in such case we should load quite heavy picture)
  • a protection proxy — controls access to the original object (for example in cases with separate access rights to some functionality, like some content with authorization separation)
  • a smart reference — controls whether Subject should be locked (due to edit process by some other user) or counts a number of clicks on a Subject, etc

This pattern includes two main roles:

  • Proxy — maintains a reference that lets the proxy access to real subject, provides an interface identical to Subject’s for a legal substitution and controls an access to the substitued Subject.
  • Subject —defines an object that the proxy represents.

This pattern also known as a Surrogate.

In JavaScript language there is a special class named Proxy.

const proxyObject = new Proxy(subject, handlerObject);
// subject - target object
// handlerObject - object with a traps (hooks) for a specific operations with a subject

Let’s describe some of traps here:

  • get(target, property, receiver) — is triggered when specific property is red from the target object. receiver in majority of cases is a Proxy itself.
  • set(target, property, receiver) — is triggered in case of writing to a Proxy.
  • has(target, query) — is triggered in case when property existance is checked in the target object. (operator in)
const subject = {
name: 'Pavel',
age: 20
};
const proxyObject = new Proxy(subject, {
has(target, property) {
console.log(`${property} is accessed`);
return true;
}
});
console.log('someNonExistingProp' in proxyObject); // true
  • deleteProperty — is triggered on delete operation. Should return true if delete was successful
  • apply(target, thisArg, argsList) — is triggered when proxy object is a function and right after calling it. thisArg is a context of calling ( this ), and argsList is a list of an arguments passed to a function
  • construct(target, argsList) — is triggered when instantiation process appear (with new operator).

All the list and more information about Proxy class implementation you can find here.

Example of use

Let’s create a coffee machine with internal state (isOn) and two controls to turn it on and off. The responsibility of proxy would be to control the access to these methods — if machine is turned on already there is no need to turn it on again. The same for situation when machine is turned off. In such cases we want to show message to the user that machine is turned on or off already without any further action.

This was a simple example of the access proxy.

Profit

The Proxy pattern introduces a level of indirection when accessing an object.

This indirection has many uses:

  • protection proxies allow control of accessing process
  • smart references proxies allow collecting information about subject usage
  • virtual proxies can perform variety of optimizations (like creating object on demand and avoid system overload)
  • remote proxies can provide an access to a remote object from a different address space

Another useful approach is called copy-on-write optimization. It’s related to the creation on demand. Copying a large and complicated object can be an expensive operation and if copy is never modified it makes no use for such cost. Using such approach we ensure that copying process is used only if we need to return complicated object which is modified. If not, we should return just a link to existing one and increment a reference count to it.

Weak places

The Proxy pattern introduces a level of indirection when accessing an object.

This leads to creation of additional instances and in some simple cases could be an overhead.

Conclusion

The main collaboration for a Proxy pattern: it forwards requests to Subject when appropriate, depending on the kind of proxy.

There are several common use case for the Proxy pattern:

  • remote proxy
  • virtual proxy
  • protection proxy
  • smart reference proxy

Proxy object wraps a Subject itself. Generally, for the safety, you can even rewrite a link to an original Subject:

let payload = {
name: 'Pavel',
age: 20
};
payload = new Proxy(payload, {
... // some proxy hooks
});
// payload object here is already wrapped by proxy

There are some other related design patterns such as Adapter and Decorator.

Adapter provides a different interface to the object it adapts and Proxy provides the same interface as its subject. And Proxy pattern is used also for access protection which can refuse to perform an operation.

Decorator adds one or more responsibilities to an object, whereas a Proxy controls access to a wrapped object. However decorators can have similar implementation as proxies.

If you found this article helpful, please hit the 👏 button and feel free to comment below!

--

--