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.
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.
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.
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.
instant proxy: just replace the original function with yours.
Many More Options, Still
For more information on design patterns, more options for implementing them, and many other very useful patterns, checkout these resources:
- The infamous “Gang of Four” (GoF) design patterns book – the original source
- OODesign.com – Object Oriented Design Patterns