Proxies And Decorators In JavaScript
Proxies and Decorators are both design patterns in software development – recipes that provide common solution to common problems. I largely group Proxies and Decorators in to the same category and use them interchangeably because the implementation between them is 99% the same in most language – especially in JavaScript. The important distinction between them – as with any design pattern – is the intent of the pattern.
Proxies
The intent of a Proxy object is to forward a call on to another service or object, without the original caller knowing.
Think about the term “proxy” on the internet. If you have a proxy server set up on your network, all of the calls that you make to get out to the internet are actually made to this proxy server. The proxy server then makes the actual call to the real service or resource for you. When the real resource is returned to the proxy server, it may do something with that resource before it returns it to you, the original requester.
Proxy objects are the same in software. You make a call to a resource or service and the call that you make is handled by an object that can figure out how to make the real call, possibly pre-process the results and send any response you need, back to you.
Decorators
The intent of a Decorator is to provide additional functionality on top of an existing function or object. That is, the original code that you were intending to call will still be called, but the decorator has provided additional code or logic that will also get run in order to do something else.
Think about a 3rd party software reseller or VAR (value-added reseller). When you want to make a purchase, you could go through the company that produces the software. Chances are, though, if you are working for a company of sufficient size, you are going to make the purchase through a 3rd party reseller. The 3rd party adds value to the purchase by offering discounts and incentives that the original maker can’t provide. The reseller can do this because you have an account with them and you make a large number of purchases through them. The additional services and incentives may be consultation and recommendation to make sure you’re getting what you need, it may be discounts on even small orders, or it may be “buy this and get that for free” for unrelated items. This additional service sits on top of your intent to buy the software or package that you need. You still get to buy it, but you also get other benefits.
A decorator in software can work the same way. You may call out to a particular object or service and end up executing more code than you originally thought, while still getting the response that you need.
Proxies And Decorators In JavaScript
If the lines between these two patterns are getting a bit blurry in your mind – yes, they are blurry. The difference in the intent between these two patterns may be large enough to describe easily, but the implementation between them is largely the same.
In raw JavaScript, proxies and decorators can both be facilitated with the same code, such as this:
This is actually the implementation of the Underscorejs `wrap` method. It’s a very handy little tool that lets us easily implement both proxies and decorators.
The difference, again, comes back to the intent of the usage. If I’m intending this to be used as a proxy, I may simply forward the call on to another function:
If I’m intending this to be a decorator, I may want to call the original function while providing some additional logic that manipulates the original function’s response:
The implementation of both of these patterns is largely the same in this example, but the intent is different which is what determines the specific pattern that I’m using.
Simplifying Proxies
One of the great things about JavaScript is our ability to build Frankenstein monsters out of spare parts (as one of my clients recently put it). We can pull arms and legs and heads off a number of different objects and assemble them in to some monstrosity at runtime, allowing us to create the object that behaves the way we want.
The ability to mash objects together and replace parts as needed means we can greatly simplify proxies in JavaScript. In fact, if we are intending to wholesale replace a function with another function that simply proxies out to another service, we can get rid of the boilerplate ‘wrap’ method entirely and jump straight to method replacement:
instant proxy: just replace the original function with yours.
Many More Options, Still
JavaScript is a very flexible language, as we’ve seen. We can implement the same core functionality and capabilities in many different ways. And there are still more ways that we could approach these patterns. That’s the beauty of design patterns, in my mind. They are not prescriptive answers. They are recipes for solutions. It’s up to us, the chef writing the code, to mix and match the recipes and to augment, simplify, deconstruct and reconstitute these patterns in meaningful ways.
For more information on design patterns, more options for implementing them, and many other very useful patterns, checkout these resources:
- Addy Osmani’s Essential JavaScript Design Patterns (a must read / reference)
- Stefan Stoyanov’s JavaScript Patterns book – not strictly “design patterns” but includes many design patterns
- The infamous “Gang of Four” (GoF) design patterns book – the original source
- OODesign.com – Object Oriented Design Patterns
Once again, feel free to drop links to your favorite design pattern resources – especially those that relate to JavaScript – in the comments.